/home/cyniu/GIT/WiringPi/wiringPi/wiringPi.h
1
/*
2
 * wiringPi.h:
3
 *	Arduino like Wiring library for the Raspberry Pi.
4
 *	Copyright (c) 2012-2017 Gordon Henderson
5
 ***********************************************************************
6
 * This file is part of wiringPi:
7
 *	https://projects.drogon.net/raspberry-pi/wiringpi/
8
 *
9
 *    wiringPi is free software: you can redistribute it and/or modify
10
 *    it under the terms of the GNU Lesser General Public License as published by
11
 *    the Free Software Foundation, either version 3 of the License, or
12
 *    (at your option) any later version.
13
 *
14
 *    wiringPi is distributed in the hope that it will be useful,
15
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *    GNU Lesser General Public License for more details.
18
 *
19
 *    You should have received a copy of the GNU Lesser General Public License
20
 *    along with wiringPi.  If not, see <http://www.gnu.org/licenses/>.
21
 ***********************************************************************
22
 */
23
24
#ifndef	__WIRING_PI_H__
25
#define	__WIRING_PI_H__
26
27
// C doesn't have true/false by default and I can never remember which
28
//	way round they are, so ...
29
//	(and yes, I know about stdbool.h but I like capitals for these and I'm old)
30
31
#ifndef	TRUE
32
#  define	TRUE	(1==1)
33
#  define	FALSE	(!TRUE)
34
#endif
35
36
// GCC warning suppressor
37
38
#define	UNU	__attribute__((unused))
39
40
// Mask for the bottom 64 pins which belong to the Raspberry Pi
41
//	The others are available for the other devices
42
43
#define	PI_GPIO_MASK	(0xFFFFFFC0)
44
45
// Handy defines
46
47
// wiringPi modes
48
49
#define	WPI_MODE_PINS		 0
50
#define	WPI_MODE_GPIO		 1
51
#define	WPI_MODE_GPIO_SYS	 2
52
#define	WPI_MODE_PHYS		 3
53
#define	WPI_MODE_PIFACE		 4
54
#define	WPI_MODE_UNINITIALISED	-1
55
56
// Pin modes
57
58
#define	INPUT			 0
59
#define	OUTPUT			 1
60
#define	PWM_OUTPUT		 2
61
#define	GPIO_CLOCK		 3
62
#define	SOFT_PWM_OUTPUT		 4
63
#define	SOFT_TONE_OUTPUT	 5
64
#define	PWM_TONE_OUTPUT		 6
65
3
66
#define	LOW			 0
0
67
#define	HIGH			 1
68
69
// Pull up/down/none
70
71
#define	PUD_OFF			 0
72
#define	PUD_DOWN		 1
73
#define	PUD_UP			 2
74
75
// PWM
76
77
#define	PWM_MODE_MS		0
78
#define	PWM_MODE_BAL		1
79
80
// Interrupt levels
81
82
#define	INT_EDGE_SETUP		0
83
#define	INT_EDGE_FALLING	1
84
#define	INT_EDGE_RISING		2
85
#define	INT_EDGE_BOTH		3
86
87
// Pi model types and version numbers
88
//	Intended for the GPIO program Use at your own risk.
89
90
#define	PI_MODEL_A		 0
91
#define	PI_MODEL_B		 1
92
#define	PI_MODEL_AP		 2
93
#define	PI_MODEL_BP		 3
94
#define	PI_MODEL_2		 4
95
#define	PI_ALPHA		 5
96
#define	PI_MODEL_CM		 6
97
#define	PI_MODEL_07		 7
98
#define	PI_MODEL_3		 8
99
#define	PI_MODEL_ZERO		 9
100
#define	PI_MODEL_CM3		10
101
#define	PI_MODEL_ZERO_W		12
102
#define	PI_MODEL_3P 		13
103
104
#define	PI_VERSION_1		0
105
#define	PI_VERSION_1_1		1
106
#define	PI_VERSION_1_2		2
107
#define	PI_VERSION_2		3
108
109
#define	PI_MAKER_SONY		0
110
#define	PI_MAKER_EGOMAN		1
111
#define	PI_MAKER_EMBEST		2
112
#define	PI_MAKER_UNKNOWN	3
113
114
extern const char *piModelNames    [16] ;
115
extern const char *piRevisionNames [16] ;
116
extern const char *piMakerNames    [16] ;
117
extern const int   piMemorySize    [ 8] ;
118
119
120
//	Intended for the GPIO program Use at your own risk.
121
122
// Threads
123
124
#define	PI_THREAD(X)	void *X (UNU void *dummy)
125
126
// Failure modes
127
128
#define	WPI_FATAL	(1==1)
129
#define	WPI_ALMOST	(1==2)
130
131
132
// wiringPiNodeStruct:
133
//	This describes additional device nodes in the extended wiringPi
134
//	2.0 scheme of things.
135
//	It's a simple linked list for now, but will hopefully migrate to 
136
//	a binary tree for efficiency reasons - but then again, the chances
137
//	of more than 1 or 2 devices being added are fairly slim, so who
138
//	knows....
139
140
struct wiringPiNodeStruct
141
{
142
  int     pinBase ;
143
  int     pinMax ;
144
145
  int          fd ;	// Node specific
146
  unsigned int data0 ;	//  ditto
147
  unsigned int data1 ;	//  ditto
148
  unsigned int data2 ;	//  ditto
149
  unsigned int data3 ;	//  ditto
150
151
           void   (*pinMode)          (struct wiringPiNodeStruct *node, int pin, int mode) ;
152
           void   (*pullUpDnControl)  (struct wiringPiNodeStruct *node, int pin, int mode) ;
153
           int    (*digitalRead)      (struct wiringPiNodeStruct *node, int pin) ;
154
//unsigned int    (*digitalRead8)     (struct wiringPiNodeStruct *node, int pin) ;
155
           void   (*digitalWrite)     (struct wiringPiNodeStruct *node, int pin, int value) ;
156
//         void   (*digitalWrite8)    (struct wiringPiNodeStruct *node, int pin, int value) ;
157
           void   (*pwmWrite)         (struct wiringPiNodeStruct *node, int pin, int value) ;
158
           int    (*analogRead)       (struct wiringPiNodeStruct *node, int pin) ;
159
           void   (*analogWrite)      (struct wiringPiNodeStruct *node, int pin, int value) ;
160
161
  struct wiringPiNodeStruct *next ;
162
} ;
163
164
extern struct wiringPiNodeStruct *wiringPiNodes ;
165
166
// Export variables for the hardware pointers
167
168
extern volatile unsigned int *_wiringPiGpio ;
169
extern volatile unsigned int *_wiringPiPwm ;
170
extern volatile unsigned int *_wiringPiClk ;
171
extern volatile unsigned int *_wiringPiPads ;
172
extern volatile unsigned int *_wiringPiTimer ;
173
extern volatile unsigned int *_wiringPiTimerIrqRaw ;
174
175
176
// Function prototypes
177
//	c++ wrappers thanks to a comment by Nick Lott
178
//	(and others on the Raspberry Pi forums)
179
180
#ifdef __cplusplus
181
extern "C" {
182
#endif
183
184
// Data
185
186
// Internal
187
188
extern int wiringPiFailure (int fatal, const char *message, ...) ;
189
190
// Core wiringPi functions
191
192
extern struct wiringPiNodeStruct *wiringPiFindNode (int pin) ;
193
extern struct wiringPiNodeStruct *wiringPiNewNode  (int pinBase, int numPins) ;
194
195
extern void wiringPiVersion	(int *major, int *minor) ;
196
extern int  wiringPiSetup       (void) ;
197
extern int  wiringPiSetupSys    (void) ;
198
extern int  wiringPiSetupGpio   (void) ;
199
extern int  wiringPiSetupPhys   (void) ;
200
201
extern          void pinModeAlt          (int pin, int mode) ;
202
extern          void pinMode             (int pin, int mode) ;
203
extern          void pullUpDnControl     (int pin, int pud) ;
204
extern          int  digitalRead         (int pin) ;
205
extern          void digitalWrite        (int pin, int value) ;
206
extern unsigned int  digitalRead8        (int pin) ;
207
extern          void digitalWrite8       (int pin, int value) ;
208
extern          void pwmWrite            (int pin, int value) ;
209
extern          int  analogRead          (int pin) ;
210
extern          void analogWrite         (int pin, int value) ;
211
212
// PiFace specifics 
213
//	(Deprecated)
214
215
extern int  wiringPiSetupPiFace (void) ;
216
extern int  wiringPiSetupPiFaceForGpioProg (void) ;	// Don't use this - for gpio program only
217
218
// On-Board Raspberry Pi hardware specific stuff
219
220
extern          int  piGpioLayout        (void) ;
221
extern          int  piBoardRev          (void) ;	// Deprecated
222
extern          void piBoardId           (int *model, int *rev, int *mem, int *maker, int *overVolted) ;
223
extern          int  wpiPinToGpio        (int wpiPin) ;
224
extern          int  physPinToGpio       (int physPin) ;
225
extern          void setPadDrive         (int group, int value) ;
226
extern          int  getAlt              (int pin) ;
227
extern          void pwmToneWrite        (int pin, int freq) ;
228
extern          void pwmSetMode          (int mode) ;
229
extern          void pwmSetRange         (unsigned int range) ;
230
extern          void pwmSetClock         (int divisor) ;
231
extern          void gpioClockSet        (int pin, int freq) ;
232
extern unsigned int  digitalReadByte     (void) ;
233
extern unsigned int  digitalReadByte2    (void) ;
234
extern          void digitalWriteByte    (int value) ;
235
extern          void digitalWriteByte2   (int value) ;
236
237
// Interrupts
238
//	(Also Pi hardware specific)
239
240
extern int  waitForInterrupt    (int pin, int mS) ;
241
extern int  wiringPiISR         (int pin, int mode, void (*function)(void)) ;
242
243
// Threads
244
245
extern int  piThreadCreate      (void *(*fn)(void *)) ;
246
extern void piLock              (int key) ;
247
extern void piUnlock            (int key) ;
248
249
// Schedulling priority
250
251
extern int piHiPri (const int pri) ;
252
253
// Extras from arduino land
254
255
extern void         delay             (unsigned int howLong) ;
256
extern void         delayMicroseconds (unsigned int howLong) ;
257
extern unsigned int millis            (void) ;
258
extern unsigned int micros            (void) ;
259
260
#ifdef __cplusplus
261
}
262
#endif
263
264
#endif
/home/cyniu/GIT/malina/iDom_server_OOP/libs/Statistic/statistic_test/../statistic.h
1
#ifndef STATISTIC_H
2
#define STATISTIC_H
3
#include <iostream>
4
#include <deque>
5
#include <numeric>
6
#include <algorithm>
7
#include <sstream>
8
#include <cmath>
9
#include <vector>
10
11
template <class T>
12
class STATISTIC
13
{
14
public:
15
    STATISTIC(unsigned int size): m_size(size)
245
16
    {
245
17
245
18
    }
3
19
    void resize(unsigned int i){
3
20
        if (i < m_size){
24
21
            while(m_dequeue.size()> i){
21
22
                pop_front();
21
23
            }
3
24
        }
3
25
        m_size = i;
3
26
    }
78
27
    T size(){
78
28
        return  static_cast<T>(m_dequeue.size());
78
29
    }
10
30
    void push_front(T v){
10
31
        if (m_dequeue.size() >= m_size){
1
32
            pop_back();
1
33
        }
10
34
        m_dequeue.push_front(v);
10
35
    }
295
36
    void push_back(T v){
295
37
        if (m_dequeue.size() >= m_size){
2
38
            pop_front();
2
39
        }
295
40
        m_dequeue.push_back(v);
295
41
    }
3
42
    void pop_back(){
3
43
        m_dequeue.pop_back();
3
44
        // std::cout <<"pop_back"<<std::endl;
3
45
    }
23
46
    void pop_front(){
23
47
        m_dequeue.pop_front();
23
48
        // std::cout <<"pop_front"<<std::endl;
23
49
    }
50
    ///////////////////////////////////////////// statistic /////////////////////////////
5
51
    T median(){
5
52
        auto backup = m_dequeue;
5
53
        std::sort(backup.begin(), backup.end());
5
54
        if (backup.size() % 2 != 0){
3
55
            return backup[backup.size() / 2];
3
56
        }
2
57
        else{
2
58
            T m = backup[backup.size() / 2] + backup[(backup.size() / 2)-1];
2
59
            return m /2 ;
2
60
        }
5
61
    }
23
62
    T sum(){
23
63
        return std::accumulate(m_dequeue.begin(), m_dequeue.end(), static_cast<T>(0));
23
64
    }
65
23
66
    T average(){
23
67
        T av  = sum() /size();
23
68
        return av;
23
69
    }
70
5
71
    T max(){
5
72
        T max = m_dequeue[0];
40
73
        for (auto v : m_dequeue){
40
74
            if (v > max){
13
75
                max = v;
13
76
            }
40
77
        }
5
78
        return max;
5
79
    }
80
5
81
    T min(){
5
82
        T min = m_dequeue[0];
40
83
        for (auto v : m_dequeue){
40
84
            if (v < min){
3
85
                min = v;
3
86
            }
40
87
        }
5
88
        return min;
5
89
    }
90
1
91
    T range(){
1
92
        return max() - min();
1
93
    }
94
6
95
    T standardDeviation(){
6
96
        double standardDeviation = 0.0;
6
97
        T _av = average();
6
98
38
99
        for(int i = 0; i < size(); ++i){
32
100
            standardDeviation += pow(m_dequeue.at(i) - _av, 2);
32
101
        }
6
102
        return sqrt(standardDeviation / size());
6
103
    }
104
3
105
    T coefficientOfVariation(){
3
106
3
107
        return (standardDeviation()/average()) /** 100*/;
3
108
    }
109
13
110
    T mode(){
13
111
13
112
        T _mode = 0;
13
113
        T _modeTemp = 0;
13
114
        int counter = 1;
13
115
        int modeCounter = 1;
13
116
        auto backup = m_dequeue;
13
117
        if(m_dequeue.size() == 1)
3
118
        {
3
119
            return m_dequeue.at(0);
3
120
        }
10
121
        std::sort(backup.begin(), backup.end());
10
122
#ifdef BT_TEST
10
123
        std::cout << " " << std::endl;
10
124
        for (auto i : backup)
89
125
        {
89
126
            std::cout << i << " ";
89
127
        }
10
128
        std::cout << " " << std::endl;
10
129
#endif
10
130
        _mode = _modeTemp = backup.at(0);
10
131
        backup.pop_front();
10
132
        for (auto b : backup)
79
133
        {
79
134
            if (_modeTemp == b)
15
135
            {
15
136
                modeCounter++;
15
137
            }
79
138
            else
64
139
            {
64
140
                _modeTemp = b;
64
141
                modeCounter = 1;
64
142
            }
79
143
79
144
            if(counter < modeCounter)
8
145
            {
8
146
                counter = modeCounter;
8
147
                _mode = _modeTemp;
8
148
            }
79
149
        }
10
150
#ifdef BT_TEST
10
151
        std::cout << " moda: " << _mode << " wystepuje razy " << counter << std::endl;
10
152
#endif
10
153
        return _mode;
13
154
    }
155
156
    float trend(){
157
        int down = 0;
158
        int eq = 0;
159
        int up = 0;
160
        int lp = 0;
161
        T diff = 0;
162
        T first = m_dequeue[0];
163
164
        for (auto i = 1 ; i < m_dequeue.size(); ++i){
165
            if (first < m_dequeue[i]){
166
                up++;
167
                if (m_dequeue[i] - first > diff){
168
                    diff = m_dequeue[i] - first;
169
                    lp = i;
170
                }
171
            }
172
            if (first == m_dequeue[i]){ eq++;}
173
            if (first > m_dequeue[i]){
174
                if (diff < first - m_dequeue[i] ){
175
                    diff = first - m_dequeue[i];
176
                    lp = i;
177
                }
178
                down++;
179
            }
180
            first = m_dequeue[i];
181
        }
182
        std::cout <<"up "<<up<<" eq "<< eq << " down "<< down <<" max diff "<< diff<<" lp "<<lp << std::endl;
183
        return 2.2;
184
    }
185
8
186
    bool isMoreDiff(T diff){
8
187
        if (m_dequeue.size()>2){
6
188
            T d = m_dequeue.at( m_dequeue.size()-2)
6
189
                    - m_dequeue.at( m_dequeue.size() - 1);
6
190
            d = fabs(d);
6
191
            if (d > diff && m_alarm == false){
2
192
                m_alarm = true;
2
193
                return true;
2
194
            }
4
195
            if (d <= diff){
4
196
                m_alarm = false;
4
197
                return false;
4
198
            }
4
199
        }
2
200
        return false;
8
201
    }
3
202
    std::pair<double,double> getLast2(){
3
203
        if (m_dequeue.size()>2){
2
204
            return std::make_pair(static_cast<double>(m_dequeue.at( m_dequeue.size()-2)),
2
205
                                  static_cast<double>(m_dequeue.at( m_dequeue.size()-1))    );
2
206
        }
3
207
#ifdef BT_TEST
1
208
        puts("no data - return 0.0 0.0");
1
209
#endif
1
210
        return std::make_pair(0.0,0.0);
3
211
    }
212
213
    /////////////////////////////////////////////////////////////////////////////////////
14
214
    void print(){
71
215
        for(auto n : m_dequeue){
71
216
            std::cout << ","<< n ;
71
217
        }
14
218
        std::cout << " " <<std::endl;
14
219
    }
220
221
3
222
    std::string stats(){
3
223
3
224
        std::stringstream ss(" brak danych =(");
3
225
        if(size()>0)
3
226
        {
3
227
            ss.str("");
3
228
            ss <<"rozmiar tablicy: "<< size() <<std::endl
3
229
              << "min: "<< min() <<std::endl
3
230
              << "max: "<< max()<<std::endl
3
231
              << "srednia " << average() <<std::endl
3
232
              << "mediana " << median()  <<std::endl
3
233
              << "odchylenie st "<< standardDeviation() << std::endl
3
234
              << "wspolczynnik zmiennosci " << coefficientOfVariation() <<"%"<< std::endl
3
235
              << "Dominanta " << mode();
3
236
3
237
3
238
            ss << std::endl
3
239
               << "data " <<  std::endl;
16
240
            for(auto n : m_dequeue){
16
241
                ss << "|"<< n ;
16
242
            }
3
243
        }
3
244
        ss <<  std::endl;
3
245
        return ss.str();
3
246
    }
247
248
private:
249
    unsigned int m_size;
250
    std::deque <T> m_dequeue;
251
    bool m_alarm = false;
252
};
253
254
#endif // STATISTIC_H
/home/cyniu/GIT/malina/iDom_server_OOP/libs/Statistic/statistic_test/statistic_BT.cpp
1
#include <gtest/gtest.h>
2
#include <gmock/gmock.h>
3
#include "../statistic.h"
4
5
class StatisticClass_fixture : public ::testing::Test
6
{
7
public:
8
    STATISTIC<double> average;
9
    StatisticClass_fixture(): average(12)
7
10
    {
7
11
    }
12
    void SetUp() final
7
13
    {
7
14
        average.push_back(1);
7
15
        average.push_back(1);
7
16
        average.push_back(2);
7
17
        average.push_back(2);
7
18
        average.push_back(3);
7
19
        average.push_back(3);
7
20
        average.push_back(4);
7
21
        average.push_back(4);
7
22
        average.push_back(-5);
7
23
        average.push_back(-5);
7
24
        average.push_back(6);
7
25
        average.push_back(6);
7
26
    }
27
    void TearDown() final
7
28
    {
7
29
7
30
    }
31
};
32
33
TEST_F(StatisticClass_fixture, range)
1
34
{
1
35
    EXPECT_DOUBLE_EQ(average.average() , 1.8333333333333333);
1
36
    EXPECT_EQ(average.range(), 11);
1
37
}
38
39
TEST_F(StatisticClass_fixture, average)
1
40
{
1
41
    EXPECT_DOUBLE_EQ(average.average() , 1.8333333333333333);
1
42
    std::string ret = average.stats();
1
43
    EXPECT_THAT(ret, testing::HasSubstr("max"));
1
44
}
45
TEST_F(StatisticClass_fixture, averageOne)
1
46
{
1
47
    average.resize(1);
1
48
    average.push_back(1);
1
49
    EXPECT_DOUBLE_EQ(average.average() , 1.0);
1
50
}
51
TEST_F(StatisticClass_fixture, median)
1
52
{
1
53
    EXPECT_EQ(average.median(),2.5f);
1
54
}
55
TEST(StatisticClass, medianOne)
1
56
{
1
57
    STATISTIC<double> average(1);
1
58
    average.push_back(1);
1
59
    EXPECT_EQ(average.median(), 1.0f);
1
60
}
61
TEST_F(StatisticClass_fixture, min)
1
62
{
1
63
    EXPECT_EQ(average.min(),-5.0f);
1
64
}
65
TEST_F(StatisticClass_fixture, max)
1
66
{
1
67
    EXPECT_EQ(average.max(),6);
1
68
}
69
TEST_F(StatisticClass_fixture, push_and_pop)
1
70
{
1
71
    average.pop_back();
1
72
    EXPECT_EQ(average.size(),11);
1
73
    average.push_front(3.9);
1
74
    EXPECT_EQ(average.size(),12);
1
75
    average.pop_back();
1
76
    EXPECT_EQ(average.size(),11);
1
77
}
78
79
TEST(StatisticClass, resize)
1
80
{
1
81
    unsigned int s = 3;
1
82
    STATISTIC<double> average(12);
1
83
    average.push_back(1);
1
84
    average.push_back(2);
1
85
    average.push_back(3);
1
86
    average.push_back(4);
1
87
    average.push_back(5);
1
88
    average.push_front(44);
1
89
    average.push_front(45);
1
90
    average.print();
1
91
    average.resize(s);
1
92
1
93
    EXPECT_EQ(average.size(),static_cast<double>(s));
1
94
1
95
    auto data = average.getLast2();
1
96
    average.print();
1
97
1
98
    EXPECT_EQ(data.first,4.0);
1
99
    EXPECT_EQ(data.second,5.0);
1
100
}
101
102
TEST(StatisticClass, getLast2_empty)
1
103
{
1
104
    unsigned int s = 1;
1
105
    STATISTIC<double> average(12);
1
106
    average.push_back(1);
1
107
    average.push_back(2);
1
108
    average.push_back(3);
1
109
    average.push_back(4);
1
110
    average.push_back(5);
1
111
    average.push_front(44);
1
112
    average.push_front(45);
1
113
    average.print();
1
114
    average.resize(s);
1
115
    average.push_front(33);
1
116
1
117
    EXPECT_EQ(average.size(),static_cast<double>(s));
1
118
1
119
    auto data = average.getLast2();
1
120
    average.print();
1
121
1
122
    EXPECT_EQ(data.first,0.0);
1
123
    EXPECT_EQ(data.second,0.0);
1
124
}
125
126
TEST(StatisticClass, moreDiff)
1
127
{
1
128
    STATISTIC<double> average(12);
1
129
    average.push_back(1);
1
130
    average.push_back(2);
1
131
    average.push_back(30);
1
132
    average.push_back(4);
1
133
    average.push_back(5);
1
134
    average.push_front(44);
1
135
    average.push_front(45);
1
136
    average.print();
1
137
1
138
    EXPECT_FALSE(average.isMoreDiff(2.2));
1
139
1
140
    average.push_back(7.3);
1
141
    average.print();
1
142
1
143
    EXPECT_TRUE(average.isMoreDiff(2.2));
1
144
}
145
146
TEST(StatisticClass, moreDiff_wrong)
1
147
{
1
148
    STATISTIC<double> average(1);
1
149
    average.push_back(1);
1
150
1
151
    average.print();
1
152
1
153
    EXPECT_FALSE(average.isMoreDiff(2.2));
1
154
1
155
    average.push_back(7.3);
1
156
    average.print();
1
157
1
158
    EXPECT_FALSE(average.isMoreDiff(2.2));
1
159
}
160
161
TEST(StatisticClass, noMoreDiff)
1
162
{
1
163
    STATISTIC<double> average(12);
1
164
    average.push_back(1);
1
165
    average.push_back(2);
1
166
    average.push_back(30);
1
167
    average.push_back(4);
1
168
    average.push_back(5);
1
169
    average.push_front(44);
1
170
    average.push_front(45);
1
171
    average.print();
1
172
1
173
    EXPECT_FALSE(average.isMoreDiff(6.2));
1
174
1
175
    average.push_back(7.3);
1
176
    average.print();
1
177
1
178
    EXPECT_FALSE(average.isMoreDiff(9.2));
1
179
}
180
181
TEST(StatisticClass, mode)
1
182
{
1
183
    STATISTIC<double> average(22);
1
184
    average.push_back(29.62);
1
185
    average.push_back(29.71);
1
186
    average.push_back(30.19);
1
187
    average.push_back(33.5);
1
188
    average.push_back(30.31);
1
189
    average.push_back(30.81);
1
190
    average.push_back(30.87);
1
191
    average.push_back(31.25);
1
192
    average.push_back(31.31);
1
193
    average.push_back(31.56);
1
194
    average.push_back(31.87);
1
195
    average.push_back(31.94);
1
196
    average.push_back(32.13);
1
197
    average.push_back(32.13);  //to
1
198
    average.push_back(32.63);
1
199
1
200
    average.print();
1
201
    std::cout << "1 MODE: " << average.mode() << std::endl;
3
202
    EXPECT_DOUBLE_EQ(32.13,average.mode()) << "ZLA DOMINANTA 32.13";
1
203
    average.push_back(33.5);
1
204
    average.push_back(33.5);
1
205
    std::cout << "2 MODE: " << average.mode() << std::endl;
3
206
    EXPECT_DOUBLE_EQ(33.5,average.mode()) << "ZLA DOMINANTA 33.5";
1
207
}
208
TEST(StatisticClass, modeOne)
1
209
{
1
210
    STATISTIC<double> average(1);
1
211
    average.push_back(29.62);
1
212
    average.print();
1
213
    std::cout << "1 MODE: " << average.mode() << std::endl;
3
214
    EXPECT_DOUBLE_EQ(29.62,average.mode()) << "ZLA DOMINANTA 32.13";
1
215
}
216
TEST(StatisticClass, modeTwo)
1
217
{
1
218
    STATISTIC<double> average(10);
1
219
    average.push_back(29.62);
1
220
    average.push_back(28.62);
1
221
    average.print();
1
222
    std::cout << "1 MODE: " << average.mode() << std::endl;
3
223
    EXPECT_DOUBLE_EQ(28.62,average.mode()) << "ZLA DOMINANTA 32.13";
1
224
}
225
TEST(StatisticClass, modeThree)
1
226
{
1
227
    STATISTIC<double> average(10);
1
228
    average.push_back(29.62);
1
229
    average.push_back(28.62);
1
230
    average.push_back(29.63);
1
231
    average.print();
1
232
    std::cout << "1 MODE: " << average.mode() << std::endl;
3
233
    EXPECT_DOUBLE_EQ(28.62,average.mode()) << "ZLA DOMINANTA 32.13";
1
234
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/emoji/emoji.cpp
1
#include <sstream>
2
#include "emoji.h"
3
4
EMOJI::EMOJI()
0
5
{
0
6
0
7
}
8
9
std::string EMOJI::emoji(E_emoji e)
18
10
{
0
11
    switch (e) {
14
12
    case E_emoji::NORTH_EAST_ARROW:
14
13
        return HEX_STR::hexToStr("E28697");
2
14
    case E_emoji::SOUTH_EAST_ARROW:
2
15
        return HEX_STR::hexToStr("E28698");
0
16
    case E_emoji::NORTH_WEST_ARROW:
0
17
        return HEX_STR::hexToStr("E28696");
0
18
    case E_emoji::SOUTH_WEST_ARROW:
0
19
        return HEX_STR::hexToStr("E28699");
0
20
    case E_emoji::LEFT_RIGHT_ARROW:
0
21
        return HEX_STR::hexToStr("E28694");
0
22
    case E_emoji::UP_DOWN_ARROW:
0
23
        return HEX_STR::hexToStr("E28695");
0
24
    case E_emoji::ALARM_CLOCK:
0
25
        return HEX_STR::hexToStr("E28FB0");
0
26
    case E_emoji::SUN_WITH_FACE:
0
27
        return HEX_STR::hexToStr("F09F8C9E");
0
28
    case E_emoji::SNOWFLAKE:
0
29
        return HEX_STR::hexToStr("E29D84");
0
30
    case E_emoji::HEAVY_BLACK_HEART:
0
31
        return HEX_STR::hexToStr("E29DA4");
0
32
    case E_emoji::WARNING_SIGN:
0
33
        return HEX_STR::hexToStr("E29AA0");
0
34
    case E_emoji::CHART_WITH_DOWNWARDS_TREND:
0
35
        return HEX_STR::hexToStr("F09F9389");
0
36
    case E_emoji::CHART_WITH_UPWARDS_TREND:
0
37
        return HEX_STR::hexToStr("F09F9388");
2
38
    case E_emoji::THUNDER_CLOUD_AND_RAIN:
2
39
        return HEX_STR::hexToStr("E29B88");
0
40
0
41
    }
18
42
    return"ok";
18
43
}
44
45
std::string HEX_STR::hexToStr(const std::string& hex)
18
46
{
18
47
    std::string res;
18
48
    res.reserve(hex.size() / 2);
72
49
    for (unsigned int i = 0; i < hex.size(); i += 2)
54
50
    {
54
51
        std::istringstream iss(hex.substr(i, 2));
54
52
        int temp;
54
53
        iss >> std::hex >> temp;
54
54
        res += static_cast<char>(temp);
54
55
    }
18
56
    return res;
18
57
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/event_counters/event/event_command.cpp
1
#include "event_command.h"
2
3
event_command::event_command(const std::string& name):  event_counters(name)
63
4
{
63
5
63
6
}
7
8
std::string event_command::help()
1
9
{
1
10
    return "event command";
1
11
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/event_counters/event/event_mpd.cpp
1
#include "event_mpd.h"
2
3
event_mpd::event_mpd(const std::string& name): event_counters(name)
63
4
{
63
5
63
6
}
7
8
std::string event_mpd::help()
1
9
{
1
10
    return "event from MPD";
1
11
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/event_counters/event/event_pilot.cpp
1
#include "event_pilot.h"
2
3
event_pilot::event_pilot(const std::string& name): event_counters(name)
63
4
{
63
5
63
6
}
7
8
std::string event_pilot::help()
1
9
{
1
10
    return "pilot events";
1
11
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/event_counters/event/event_unknown.cpp
1
#include "event_unknown.h"
2
3
event_unknown::event_unknown(const std::string& name) : event_counters(name), name(name)
93
4
{
93
5
93
6
}
7
8
std::string event_unknown::help()
15
9
{
15
10
    return  name+" event";
15
11
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/event_counters/event/new_connect_event.cpp
1
#include "new_connect_event.h"
2
#include <iostream>
3
new_Connect_Event::new_Connect_Event(const std::string& name) : event_counters(name)
63
4
{
63
5
63
6
}
7
8
new_Connect_Event::~new_Connect_Event()
63
9
{
63
10
    std::cout << " kasujemy obiekt" << std::endl;
63
11
}
12
13
std::string new_Connect_Event::help()
2
14
{
2
15
    return "connection start event";
2
16
}
17
18
19
20
21
22
/home/cyniu/GIT/malina/iDom_server_OOP/libs/event_counters/event_counters.cpp
1
#include "event_counters.h"
2
#include <iostream>
3
#include <iomanip>
4
#include <ctime>
5
#include <sstream>
6
#include <string>
7
#include <algorithm>
8
9
event_counters::event_counters(std::string name) : eventName(std::move(name))
345
10
{
345
11
345
12
}
13
14
int event_counters::howManyEvent()
30
15
{
30
16
    std::lock_guard < std::mutex > lock ( eventMutex);
30
17
    return static_cast<int>( eventList.size() );
30
18
}
19
20
void event_counters::addEvent(const std::string& note)
4.05k
21
{
4.05k
22
    eventStruct d;
4.05k
23
    std::ostringstream oss;
4.05k
24
4.05k
25
    auto t = std::time(nullptr);
4.05k
26
    auto tm = *std::localtime(&t);
4.05k
27
    oss << std::put_time(&tm, "%d-%m-%Y %H:%M:%S");
4.05k
28
4.05k
29
    d.date = oss.str();
4.05k
30
    d.note = note;
4.05k
31
    std::lock_guard < std::mutex > lock ( eventMutex);
4.05k
32
    eventList.push_back(d);
4.05k
33
}
34
35
std::string event_counters::getEvent()
13
36
{
13
37
    std::stringstream ret;
13
38
    ret << "Event: " << help() << "\n";
13
39
    std::lock_guard < std::mutex > lock ( eventMutex);
13
40
    int k =0;
7.21k
41
    for (auto i : eventList){
7.21k
42
        ret << ++k << "\t" << i.date << "     " <<  i.note << "\n";
7.21k
43
    }
13
44
    return ret.str();
13
45
}
46
47
void event_counters::clearEvent()
1
48
{
1
49
    std::lock_guard < std::mutex > lock ( eventMutex);
1
50
    eventList.clear();
1
51
}
52
53
void event_counters::clearEvent(unsigned int from, unsigned int to)
4
54
{
4
55
    if (to < from){
1
56
        return;
1
57
    }
3
58
    auto max = static_cast<unsigned int>( eventList.size() );
3
59
3
60
    if (max < to){
2
61
        to = max;
2
62
    }
3
63
    if(max<from){
1
64
        from = max;
1
65
        to = max;
1
66
    }
3
67
    std::lock_guard < std::mutex > lock ( eventMutex);
3
68
    eventList.erase(eventList.begin()+from, eventList.begin()+to);
3
69
}
70
71
std::string event_counters::getEventName()
345
72
{
345
73
    return eventName;
345
74
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/event_counters/event_counters_handler.cpp
1
#include "event_counters_handler.h"
2
#include "event/new_connect_event.h"
3
#include "event/event_unknown.h"
4
#include "event/event_mpd.h"
5
#include "event/event_pilot.h"
6
#include "event/event_command.h"
7
8
9
event_counters_handler::event_counters_handler()
63
10
{
63
11
    std::shared_ptr <event_counters> newConnectEvent (new new_Connect_Event("connections") );
63
12
    eventCountersMap.insert(  std::make_pair( newConnectEvent->getEventName(),   newConnectEvent  )  );
63
13
63
14
    std::shared_ptr <event_counters> newUnknownEvent (new event_unknown("unknown") );
63
15
    eventCountersMap.insert(  std::make_pair( newUnknownEvent->getEventName(),   newUnknownEvent  )  );
63
16
63
17
    std::shared_ptr <event_counters> eventMPD (new event_mpd("mpd") );
63
18
    eventCountersMap.insert(  std::make_pair( eventMPD->getEventName(),   eventMPD )  );
63
19
63
20
    std::shared_ptr <event_counters> eventPilot (new event_pilot("pilot") );
63
21
    eventCountersMap.insert(  std::make_pair( eventPilot->getEventName(),   eventPilot )  );
63
22
63
23
    std::shared_ptr <event_counters> eventCommand (new event_command("command") );
63
24
    eventCountersMap.insert(  std::make_pair( eventCommand->getEventName(),   eventCommand )  );
63
25
}
26
27
std::shared_ptr<event_counters> event_counters_handler::run(const std::string& name)
4.10k
28
{
4.10k
29
4.10k
30
    if (eventCountersMap.find(name) == eventCountersMap.end()){
30
31
        addEvent(name);
30
32
    }
4.10k
33
    return  eventCountersMap[name];
4.10k
34
}
35
36
std::string event_counters_handler::getListPossibleEvents()
1
37
{
1
38
    std::string result;
1
39
7
40
    for( auto  iter= eventCountersMap.begin();iter != eventCountersMap.end(); ++iter ) {
6
41
        result+= iter->first;
6
42
        result+= "\n";
6
43
    }
1
44
    return result;
1
45
}
46
47
std::string event_counters_handler::help(const std::string& name)
2
48
{
2
49
    std::string result;
2
50
2
51
    if (name.empty()){
7
52
        for( auto  iter= eventCountersMap.begin();iter != eventCountersMap.end(); ++iter ) {
6
53
            result+= iter->second->help();
6
54
            result+= "\n------------------------------\n";
6
55
        }
1
56
    }
1
57
    else{
1
58
        result = eventCountersMap[name]->help();
1
59
    }
2
60
2
61
    return result;
2
62
}
63
std::mutex event_counters_handler::echMutex;
64
65
void event_counters_handler::addEvent(const std::string& name)
30
66
{
30
67
    std::lock_guard <std::mutex> lock(event_counters_handler::echMutex);
30
68
    std::shared_ptr <event_counters> newUnknownEvent (new event_unknown(name) );
30
69
    eventCountersMap.insert(  std::make_pair( newUnknownEvent->getEventName(),   newUnknownEvent  )  );
30
70
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/event_counters/test/event_BT.cpp
1
#include <gtest/gtest.h>
2
#include "test_data.h"
3
#include "../../../iDom_server_OOP/src/iDomTools/test/iDomTools_fixture.h"
4
#include "../event_counters_handler.h"
5
6
class event_counter_fixture : public iDomTOOLS_ClassTest
7
{
8
public:
9
     event_counters_handler mainEvent;
10
     std::string msg = "info";
11
     std::string testEvent = "testEvent";
4
12
     void preper1001Event(){
4
13
         int counter = 1000;
4
14
         EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),0);
4
15
         mainEvent.run(testEvent)->addEvent(msg);
4
16
         EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1);
4
17
         std::string returnedString = mainEvent.run(testEvent)->getEvent();
4
18
         EXPECT_THAT(returnedString, testing::HasSubstr(msg));
4
19
         EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1);
4
20
4.00k
21
         for (int i = 1; i!= counter; counter--)
3.99k
22
         {
3.99k
23
             mainEvent.run(testEvent)->addEvent(msg);
3.99k
24
             if(counter == 500)
4
25
                 mainEvent.run(testEvent)->addEvent("cyniu");
3.99k
26
         }
4
27
         EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1001);
4
28
         returnedString = mainEvent.run(testEvent)->getEvent();
4
29
         EXPECT_THAT(returnedString, testing::HasSubstr("cyniu"));
4
30
     }
31
};
32
33
TEST_F(event_counter_fixture, add_get_clear_event)
1
34
{
1
35
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),0);
1
36
    mainEvent.run(testEvent)->addEvent(msg);
1
37
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1);
1
38
    std::string returnedString = mainEvent.run(testEvent)->getEvent();
1
39
    EXPECT_THAT(returnedString, testing::HasSubstr(msg));
1
40
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1);
1
41
    mainEvent.run(testEvent)->clearEvent();
1
42
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),0);
1
43
}
44
45
TEST_F(event_counter_fixture, clear_middle_part_of_event_small_big)
1
46
{
1
47
    preper1001Event();
1
48
    mainEvent.run(testEvent)->clearEvent(400,600);
1
49
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),801);
1
50
    std::string returnedString = mainEvent.run(testEvent)->getEvent();
1
51
    EXPECT_THAT(returnedString, testing::Not(testing::HasSubstr("cyniu")));
1
52
}
53
54
TEST_F(event_counter_fixture, clear_middle_part_of_event_big_small)
1
55
{
1
56
    preper1001Event();
1
57
    mainEvent.run(testEvent)->clearEvent(600,400);
1
58
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1001);
1
59
    std::string returnedString = mainEvent.run(testEvent)->getEvent();
1
60
    EXPECT_THAT(returnedString,testing::HasSubstr("cyniu"));
1
61
}
62
63
TEST_F(event_counter_fixture, clear_middle_part_of_event_to_max)
1
64
{
1
65
    preper1001Event();
1
66
    mainEvent.run(testEvent)->clearEvent(400,1600);
1
67
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),400);
1
68
    std::string returnedString = mainEvent.run(testEvent)->getEvent();
1
69
    EXPECT_THAT(returnedString, testing::Not(testing::HasSubstr("cyniu")));
1
70
}
71
72
TEST_F(event_counter_fixture, clear_middle_part_of_event_from_max)
1
73
{
1
74
    preper1001Event();
1
75
    mainEvent.run(testEvent)->clearEvent(1400,1600);
1
76
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1001);
1
77
    std::string returnedString = mainEvent.run(testEvent)->getEvent();
1
78
    EXPECT_THAT(returnedString, testing::HasSubstr("cyniu") );
1
79
}
80
81
TEST_F(event_counter_fixture, getListPossibleEvents)
1
82
{
1
83
    mainEvent.run("INFO")->addEvent("kokolino");
1
84
   std::string returnedString = mainEvent.getListPossibleEvents();
1
85
   std::cout << "wynik: " << returnedString << std::endl;
1
86
   EXPECT_THAT(returnedString, testing::HasSubstr("INFO") );
1
87
}
88
89
TEST_F(event_counter_fixture, getHelp)
1
90
{
1
91
    mainEvent.run("INFO")->addEvent("kokolino");
1
92
   std::string returnedString = mainEvent.help("connections");
1
93
   std::cout << "wynik: " << returnedString << std::endl;
1
94
   EXPECT_THAT(returnedString, testing::HasSubstr("start") );
1
95
   returnedString = mainEvent.help("");
1
96
   std::cout << "wynik: " << returnedString << std::endl;
1
97
   EXPECT_THAT(returnedString, testing::HasSubstr("pilot") );
1
98
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/sunrise-sunset/sunriseset.cpp
1
#include "sunriseset.h"
2
3
double SunRiseSet::FNday(int y, int m, int d, float h)
26
4
{
26
5
    long int luku = - 7 * (y + (m + 9)/12)/4 + 275*m/9 + d;
26
6
26
7
    // Typecasting needed for TClite on PC DOS at least, to avoid product overflow
26
8
    luku+= (long int)y*367;
26
9
26
10
    return (double)luku - 730531.5 + h/24.0;
26
11
}
12
double SunRiseSet::FNrange(double x)
78
13
{
78
14
    double b = x / tpi;
78
15
    double a = tpi * (b - (long)(b));
78
16
    if (a < 0) a = tpi + a;
78
17
    return a;
78
18
}
19
20
double SunRiseSet::f0(double lat, double declin)
26
21
{
26
22
    double fo,dfo;
26
23
    // Correction: different sign at S HS
26
24
    dfo = rads*(0.5*SunDia + AirRefr); if (lat < 0.0) dfo = -dfo;
26
25
    fo = tan(declin + dfo) * tan(lat*rads);
26
26
26
27
    if (fo > 0.99999) fo=1.0; // to avoid overflow //
26
28
    fo = asin(fo) + pi/2.0;
26
29
    return fo;
26
30
}
31
32
double SunRiseSet::f1(double lat, double declin)
0
33
{
0
34
    double fi,df1;
0
35
    // Correction: different sign at S HS
0
36
    df1 = rads * 6.0; if (lat < 0.0) df1 = -df1;
0
37
    fi = tan(declin + df1) * tan(lat*rads);
0
38
0
39
    if (fi > 0.99999) fi=1.0; // to avoid overflow //
0
40
    fi = asin(fi) + pi/2.0;
0
41
    return fi;
0
42
}
43
44
double SunRiseSet::FNsun(double d)
26
45
{
26
46
    // mean longitude of the Sun
26
47
    L = FNrange(280.461 * rads + .9856474 * rads * d);
26
48
26
49
    // mean anomaly of the Sun
26
50
    g = FNrange(357.528 * rads + .9856003 * rads * d);
26
51
26
52
    // Ecliptic longitude of the Sun
26
53
    return FNrange(L + 1.915 * rads * sin(g) + .02 * rads * sin(2 * g));
26
54
}
55
56
Clock SunRiseSet::gethrmn(double dhr)
26
57
{
26
58
26
59
    int hr,mn;
26
60
26
61
    hr=(int) dhr;
26
62
    mn = (dhr - (double) hr)*60;
26
63
26
64
    Clock ret(hr,mn);
26
65
26
66
    return ret;
26
67
}
68
69
SunRiseSet::SunRiseSet()
53
70
{
53
71
53
72
}
73
74
void SunRiseSet::printAllData()
0
75
{
0
76
0
77
    double y,m,day,h,latit,longit;
0
78
0
79
    time_t sekunnit;
0
80
    struct tm *p;
0
81
0
82
    // get the date and time from the user
0
83
    // read system date and extract the year
0
84
0
85
    /** First get current time **/
0
86
    time(&sekunnit);
0
87
0
88
    /** Next get localtime **/
0
89
0
90
    p=localtime(&sekunnit);
0
91
    // this is Y2K compliant algorithm
0
92
    y = 1900 + p->tm_year;
0
93
0
94
    m = p->tm_mon + 1;
0
95
    day = p->tm_mday;
0
96
    h = 12;
0
97
0
98
    std::cout << "Input latitude, longitude and timezone\n";
0
99
    latit = LATITUDE;
0
100
    longit = LONGITUDE;
0
101
    // Timezone hours
0
102
    double tzone= TIMEZONE;
0
103
    double d = FNday(y, m, day, h);
0
104
0
105
    // Use FNsun to find the ecliptic longitude of the
0
106
    // Sun
0
107
    double lambda = FNsun(d);
0
108
0
109
    // Obliquity of the ecliptic
0
110
    double obliq = 23.439 * rads - .0000004 * rads * d;
0
111
0
112
    // Find the RA and DEC of the Sun
0
113
    double alpha = atan2(cos(obliq) * sin(lambda), cos(lambda));
0
114
    double delta = asin(sin(obliq) * sin(lambda));
0
115
0
116
    // Find the Equation of Time in minutes
0
117
    // Correction suggested by David Smith
0
118
    double LL = L - alpha;
0
119
    if (L < pi) LL += tpi;
0
120
    double equation = 1440.0 * (1.0 - LL / tpi);
0
121
    double ha = f0(latit,delta);
0
122
    double hb = f1(latit,delta);
0
123
    double twx = hb - ha;   // length of twilight in radians
0
124
    twx = 12.0*twx/pi;      // length of twilight in degrees
0
125
0
126
    // Conversion of angle to hours and minutes //
0
127
    daylen = degs * ha / 7.5;
0
128
    if (daylen<0.0001) {daylen = 0.0;}
0
129
    // arctic winter   //
0
130
0
131
    double riset = 12.0 - 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
0
132
    double settm = 12.0 + 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
0
133
    //double noont = riset + 12.0 * ha/pi;
0
134
    //double altmax = 90.0 + delta * degs - latit;
0
135
    // Correction suggested by David Smith
0
136
    // to express as degrees from the N horizon
0
137
0
138
    //if (delta * degs > latit ) altmax = 90.0 + latit - delta * degs;
0
139
0
140
    double twam = riset - twx;    // morning twilight begin
0
141
    double twpm = settm + twx;      // evening twilight end
0
142
0
143
    if (riset > 24.0) riset-= 24.0;
0
144
    if (settm > 24.0) settm-= 24.0;
0
145
0
146
    std::cout << "\n Sunrise and set\n";
0
147
    std::cout << "===============\n";
0
148
    std::cout << "  year  : " << y << '\n';
0
149
    std::cout << "  month : " << m << '\n';
0
150
    std::cout << "  day   : " << day << "\n\n";
0
151
    std::cout << "Days until Y2K :  " << d << '\n';
0
152
    std::cout << "Latitude :  " << latit << ", longitude:  " << longit << '\n';
0
153
    std::cout << "Timezone :  " << tzone << "\n\n";
0
154
    std::cout << "Declination : " << delta * degs << '\n';
0
155
    std::cout << "Daylength   : "<< gethrmn(daylen).m_h<<":"<<gethrmn(daylen).m_min<< " hours \n";
0
156
    std::cout << "Begin civil twilight: "<<
0
157
                 gethrmn(twam).m_h<<":"<<gethrmn(twam).m_min; std::cout << '\n';
0
158
0
159
    std::cout << "Sunrise     : "<< gethrmn(riset).m_h<<":"<<gethrmn(riset).m_min; std::cout << '\n';
0
160
    std::cout << "Sun altitude at noontime ";
0
161
0
162
0
163
    std::cout << "Sunset      : "<<
0
164
                 gethrmn(settm).m_h<<":"<<gethrmn(settm).m_min; std::cout << '\n';
0
165
    std::cout << "Civil twilight: "<<
0
166
                 gethrmn(twpm).m_h<<":"<<gethrmn(twpm).m_min; std::cout << '\n';
0
167
}
168
169
void SunRiseSet::setPosition(double LATITUDE, double LONGITUDE, int TIMEZONE)
0
170
{
0
171
    this->LATITUDE = LATITUDE;
0
172
    this->LONGITUDE = LONGITUDE;
0
173
    this->TIMEZONE = TIMEZONE;
0
174
}
175
176
int SunRiseSet::getYear()
0
177
{
0
178
    time_t sekunnit;
0
179
    struct tm *p;
0
180
0
181
    // get the date and time from the user
0
182
    // read system date and extract the year
0
183
0
184
    /** First get current time **/
0
185
    time(&sekunnit);
0
186
0
187
    /** Next get localtime **/
0
188
0
189
    p=localtime(&sekunnit);
0
190
    // this is Y2K compliant algorithm
0
191
    return 1900 + p->tm_year;
0
192
}
193
194
int SunRiseSet::getMounth()
0
195
{
0
196
    time_t sekunnit;
0
197
    struct tm *p;
0
198
0
199
    // get the date and time from the user
0
200
    // read system date and extract the year
0
201
0
202
    /** First get current time **/
0
203
    time(&sekunnit);
0
204
0
205
    /** Next get localtime **/
0
206
0
207
    p=localtime(&sekunnit);
0
208
    // this is Y2K compliant algorithm
0
209
    return p->tm_mon+1;
0
210
}
211
212
int SunRiseSet::getDay()
0
213
{
0
214
    time_t sekunnit;
0
215
    struct tm *p;
0
216
0
217
    // get the date and time from the user
0
218
    // read system date and extract the year
0
219
0
220
    /** First get current time **/
0
221
    time(&sekunnit);
0
222
    /** Next get localtime **/
0
223
0
224
    p=localtime(&sekunnit);
0
225
    // this is Y2K compliant algorithm
0
226
    return p->tm_mday;
0
227
}
228
229
Clock SunRiseSet::getSunRise()
13
230
{
13
231
    double y,m,day,h,latit,longit;
13
232
    time_t sekunnit;
13
233
    struct tm *p;
13
234
    // get the date and time from the user
13
235
    // read system date and extract the year
13
236
13
237
    /** First get current time **/
13
238
    time(&sekunnit);
13
239
13
240
    /** Next get localtime **/
13
241
    p=localtime(&sekunnit);
13
242
    // this is Y2K compliant algorithm
13
243
    y = 1900 + p->tm_year;
13
244
    m = p->tm_mon + 1;
13
245
    day = p->tm_mday;
13
246
    h = 12;
13
247
    latit = LATITUDE;
13
248
    longit = LONGITUDE;
13
249
    // Timezone hours
13
250
    double tzone = TIMEZONE;
13
251
    double d = FNday(y, m, day, h);
13
252
    // Use FNsun to find the ecliptic longitude of the
13
253
    // Sun
13
254
    double lambda = FNsun(d);
13
255
    // Obliquity of the ecliptic
13
256
    double obliq = 23.439 * rads - .0000004 * rads * d;
13
257
    // Find the RA and DEC of the Sun
13
258
    double alpha = atan2(cos(obliq) * sin(lambda), cos(lambda));
13
259
    double delta = asin(sin(obliq) * sin(lambda));
13
260
    double LL = L - alpha;
13
261
    if (L < pi) LL += tpi;
13
262
    double equation = 1440.0 * (1.0 - LL / tpi);
13
263
    double ha = f0(latit,delta);
13
264
    // Conversion of angle to hours and minutes //
13
265
    daylen = degs * ha / 7.5;
13
266
    if (daylen<0.0001) {daylen = 0.0;}
13
267
    // arctic winter   //
13
268
    double riset = 12.0 - 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
13
269
13
270
    if (riset > 24.0) riset-= 24.0;
13
271
    return  gethrmn(riset);
13
272
}
273
274
Clock SunRiseSet::getDayLength()
0
275
{
0
276
    double y,m,day,h,latit;
0
277
    time_t sekunnit;
0
278
    struct tm *p;
0
279
0
280
    // get the date and time from the user
0
281
    // read system date and extract the year
0
282
0
283
    /** First get current time **/
0
284
    time(&sekunnit);
0
285
0
286
    /** Next get localtime **/
0
287
    p=localtime(&sekunnit);
0
288
    // this is Y2K compliant algorithm
0
289
    y = 1900 + p->tm_year;
0
290
    m = p->tm_mon + 1;
0
291
    day = p->tm_mday;
0
292
    h = 12;
0
293
    latit = LATITUDE;
0
294
    double d = FNday(y, m, day, h);
0
295
0
296
    // Use FNsun to find the ecliptic longitude of the
0
297
    // Sun
0
298
    double lambda = FNsun(d);
0
299
    // Obliquity of the ecliptic
0
300
    double obliq = 23.439 * rads - .0000004 * rads * d;
0
301
    double delta = asin(sin(obliq) * sin(lambda));
0
302
    // Find the Equation of Time in minutes
0
303
    // Correction suggested by David Smith
0
304
    double ha = f0(latit,delta);
0
305
    // Conversion of angle to hours and minutes //
0
306
    daylen = degs * ha / 7.5;
0
307
    if (daylen<0.0001) {daylen = 0.0;}
0
308
    // arctic winter   //
0
309
0
310
    return  gethrmn(daylen);
0
311
}
312
313
Clock SunRiseSet::getSunSet()
13
314
{
13
315
    double y,m,day,h,latit,longit;
13
316
13
317
    time_t sekunnit;
13
318
    struct tm *p;
13
319
13
320
    // get the date and time from the user
13
321
    // read system date and extract the year
13
322
13
323
    /** First get current time **/
13
324
    time(&sekunnit);
13
325
13
326
    /** Next get localtime **/
13
327
13
328
    p=localtime(&sekunnit);
13
329
    // this is Y2K compliant algorithm
13
330
    y = 1900 + p->tm_year;
13
331
13
332
    m = p->tm_mon + 1;
13
333
    day = p->tm_mday;
13
334
    h = 12;
13
335
13
336
    latit = LATITUDE;
13
337
    longit = LONGITUDE;
13
338
    // Timezone hours
13
339
    double tzone = TIMEZONE;
13
340
13
341
    double d = FNday(y, m, day, h);
13
342
13
343
    // Use FNsun to find the ecliptic longitude of the
13
344
    // Sun
13
345
13
346
    double lambda = FNsun(d);
13
347
13
348
    // Obliquity of the ecliptic
13
349
13
350
    double obliq = 23.439 * rads - .0000004 * rads * d;
13
351
13
352
    // Find the RA and DEC of the Sun
13
353
13
354
    double alpha = atan2(cos(obliq) * sin(lambda), cos(lambda));
13
355
    double delta = asin(sin(obliq) * sin(lambda));
13
356
13
357
13
358
    // Find the Equation of Time in minutes
13
359
    // Correction suggested by David Smith
13
360
13
361
    double LL = L - alpha;
13
362
    if (L < pi) LL += tpi;
13
363
    double equation = 1440.0 * (1.0 - LL / tpi);
13
364
13
365
13
366
    double ha = f0(latit,delta);
13
367
13
368
    // Conversion of angle to hours and minutes //
13
369
    daylen = degs * ha / 7.5;
13
370
    if (daylen<0.0001) {daylen = 0.0;}
13
371
    // arctic winter   //
13
372
13
373
    //double riset = 12.0 - 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
13
374
    double settm = 12.0 + 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
13
375
13
376
    //if (riset > 24.0) riset-= 24.0;
13
377
    if (settm > 24.0) settm-= 24.0;
13
378
    return  gethrmn(settm);
13
379
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/useful/test/../useful.h
1
#ifndef Iusefull_H
2
#define Iusefull_H
3
4
#include <iostream>
5
#include <string>
6
#include <vector>
7
#include <ostream>
8
#include <chrono>
9
#include <sstream>
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <iomanip>
13
#ifndef ANDROID
14
#include "json.hpp"
15
#endif
16
17
std::vector<std::string> split_string(const std::string& s, char separator );
18
19
class useful_F_libs {
20
public:
21
    static  void write_to_mkfifo(const std::string &path, const std::string &msg);
22
    static  std::string read_from_mkfifo(const std::string &path);
23
    static size_t  WriteCallback(void *contents, size_t size, size_t nmemb, void *userp);
24
    static std::string find_tag (const std::string &temp);
25
    //////////////////// HTTP req //////////////////////////
26
    static std::string httpPost(const std::string &url, int timeoutSeconds);
27
    static std::string httpPost(const std::string &url);
28
    static void downloadFile(const std::string &url, const std::string &path, int timeoutSeconds);
29
    static std::string replaceAll(std::string str, const std::string& from, const std::string& to);
30
    static std::string removeHtmlTag(std::string &data);
31
    /////////////////////  JSON ////////////////////////////
32
33
#ifndef ANDROID
34
    static nlohmann::json getJson(const std::string &url);
35
#endif
36
};
37
namespace std
38
{
39
40
#ifdef ANDROID
41
template <typename T>
42
int stoi(T s){
43
    return atoi(s.c_str());
44
}
45
#endif
46
47
template <typename T>
48
std::string to_string(T value)
49
{
50
    std::ostringstream os ;
51
    os << value ;
52
    return os.str() ;
53
}
54
} // namespace std
55
56
template <typename T>
57
std::string to_string_with_precision(const T a_value, const int n = 4)
43
58
{
43
59
    std::ostringstream out;
43
60
    out << std::setprecision(n) << a_value;
43
61
    return out.str();
43
62
}
63
64
struct Clock{
65
private:
66
    std::time_t m_time;
67
68
public:
69
    unsigned int m_h = 0;
70
    unsigned int m_min = 0;
277
71
    Clock () {}
35
72
    Clock(std::string t){
35
73
        std::vector<std::string> vt = split_string(t,':');
35
74
        int h = std::stoi(vt.at(0));
35
75
        int m = std::stoi(vt.at(1));
35
76
        set(static_cast <unsigned int>(h),static_cast <unsigned int>(m));
35
77
    }
78
246
79
    Clock(unsigned int h, unsigned int m) {
246
80
        set(h,m);
246
81
    }
82
    /////////////////////////////////////////////////////////////////////////////////////
283
83
    void set(unsigned int h, unsigned int m){
283
84
        if (h<24 && m <60){
282
85
            this->m_h = h;
282
86
            this->m_min = m;
282
87
        }
1
88
        else {
1
89
            throw 0;
1
90
        }
283
91
    }
92
    /////////////////////////////////////////////////////////////////////////////////////
24
93
    const std::string getString(){
24
94
        std::stringstream ret;
24
95
        if (m_h < 10) {
16
96
            ret << "0";
16
97
        }
24
98
        ret << m_h;
24
99
        ret << ":";
24
100
        if (m_min < 10) {
16
101
            ret << "0";
16
102
        }
24
103
        ret << m_min;
24
104
        return ret.str();
24
105
    }
106
    /////////////////////////////////////////////////////////////////////////////////////
13
107
    bool operator == (const Clock & c){
13
108
        if ((this->m_h == c.m_h) && (this->m_min == c.m_min)){
11
109
            return true;
11
110
        }
2
111
        else{
2
112
            return false;
2
113
        }
13
114
    }
115
    /////////////////////////////////////////////////////////////////////////////////////
13
116
    bool operator != (const Clock & c){
13
117
        if ((this->m_h != c.m_h) || (this->m_min != c.m_min)){
8
118
            return true;
8
119
        }
5
120
        else{
5
121
            return false;
5
122
        }
13
123
    }
124
    /////////////////////////////////////////////////////////////////////////////////////
1
125
    friend std::ostream & operator<< (std::ostream &w ,  Clock &c) {
1
126
        return w << c.getString();
1
127
    }
128
    /////////////////////////////////////////////////////////////////////////////////////
15
129
    bool operator < (const Clock& c){
15
130
        if (this->m_h < c.m_h){
1
131
            return true;
1
132
        }
14
133
        else{
14
134
            if (this->m_h == c.m_h && this->m_min < c.m_min){
1
135
                return true;
1
136
            }
14
137
        }
13
138
        return false;
15
139
    }
140
    /////////////////////////////////////////////////////////////////////////////////////
16
141
    bool operator > (const Clock& c){
16
142
        if (this->m_h > c.m_h){
14
143
            return true;
14
144
        }
2
145
        else{
2
146
            if (this->m_h == c.m_h && this->m_min > c.m_min){
1
147
                return true;
1
148
            }
2
149
        }
1
150
        return false;
16
151
    }
152
    /////////////////////////////////////////////////////////////////////////////////////
3
153
    bool operator >= (const Clock& c){
3
154
        if (this->m_h > c.m_h){
1
155
            return true;
1
156
        }
2
157
        else if (this->m_h == c.m_h){
1
158
1
159
            if (this->m_min >= c.m_min){
1
160
                return true;
1
161
            }
1
162
        }
1
163
        return false;
3
164
    }
165
    /////////////////////////////////////////////////////////////////////////////////////
4
166
    bool operator <= (const Clock& c){
4
167
        if (this->m_h < c.m_h){
1
168
            return true;
1
169
        }
3
170
        else if (this->m_h == c.m_h){
2
171
2
172
            if (this->m_min <= c.m_min){
1
173
                return true;
1
174
            }
2
175
        }
2
176
        return false;
4
177
    }
178
    /////////////////////////////////////////////////////////////////////////////////////
54
179
    Clock  operator + (const Clock& c){
54
180
        unsigned int minutes, hours;
54
181
        minutes = m_min+ c.m_min;
54
182
        hours = m_h + c.m_h;
54
183
        if (minutes >59){
54
184
            minutes =  minutes % 60 ;
54
185
            hours+=1;
54
186
        }
54
187
        if (hours >= 24){
54
188
            hours-=24;
54
189
        }
54
190
        return  Clock(hours, minutes);
54
191
54
192
    }
193
    /////////////////////////////////////////////////////////////////////////////////////
2
194
    Clock&  operator += (const Clock& c){
2
195
        unsigned int minutes, hours;
2
196
        minutes = m_min+ c.m_min;
2
197
        hours = m_h + c.m_h;
2
198
        if (minutes >59){
1
199
            minutes =  minutes % 60 ;
1
200
            hours+=1;
1
201
        }
2
202
        if (hours >= 24){
1
203
            hours-=24;
1
204
        }
2
205
        this->m_h = hours;
2
206
        this->m_min = minutes;
2
207
        return *this;
2
208
2
209
    }
210
    /////////////////////////////////////////////////////////////////////////////////////
211
5
212
    unsigned int toSeconds(){
5
213
        return toSeconds(Clock(this->m_h, this->m_min) );
5
214
    }
215
    /////////////////////////////////////////////////////////////////////////////////////
216
6
217
    static unsigned int toSeconds(Clock t){
6
218
        return ((t.m_h*60) + t.m_min)*60;
6
219
    }
220
    /////////////////////////////////////////////////////////////////////////////////////
221
3
222
    static Clock fromSeconds(unsigned int sec){
3
223
        unsigned int h = sec/3600;
3
224
        unsigned int min = sec%3600;
3
225
        min = min/60;
3
226
        return Clock(h,min);
3
227
    }
228
    /////////////////////////////////////////////////////////////////////////////////////
229
230
    static Clock periodOfTime(Clock start, Clock end)
2
231
    {
2
232
        if (end >= start){
1
233
            return Clock::fromSeconds(end.toSeconds() - start.toSeconds()  );
1
234
        }
1
235
        else{
1
236
            return Clock::fromSeconds(end.toSeconds() + ( Clock::toSeconds(Clock(23,59))+ 60 - start.toSeconds() ) );
1
237
        }
2
238
        //return diff;
2
239
    }
240
    /////////////////////////////////////////////////////////////////////////////////////
241
    static Clock getTime()
97
242
    {
97
243
        time_t now = time(0);
97
244
        tm *ltm = localtime(&now);
97
245
        return Clock( static_cast <unsigned int>(ltm->tm_hour),static_cast <unsigned int>(ltm->tm_min) );
97
246
    }
247
    /////////////////////////////////////////////////////////////////////////////////////
248
    void stopwatchStart()
1
249
    {
1
250
        m_time = std::time(nullptr);
1
251
    }
252
    /////////////////////////////////////////////////////////////////////////////////////
253
    unsigned int  stopwatchStopAndGetResult()
1
254
    {
1
255
        return static_cast<unsigned int>(std::time(nullptr) - m_time);
1
256
    }
257
};
258
259
enum class STATE {
260
    OFF,
261
    ON,
262
    UNKNOWN,
263
    PLAY,
264
    PAUSE,
265
    STOP,
266
    ACTIVE,
267
    DEACTIVE,
268
    WORKING,
269
    DEFINE,
270
    UNDEFINE,
271
    LOCK,
272
    UNLOCK,
273
    EMPTY,
274
    FULL,
275
    SEND_OK,
276
    SEND_NOK
277
    //WARNING remember add new state to stateToString() usefull.cpp
278
};
279
280
281
std::string stateToString(STATE s);
282
283
#endif
/home/cyniu/GIT/malina/iDom_server_OOP/libs/useful/test/useful_bt.cpp
1
#include <gtest/gtest.h>
2
#include <gmock/gmock.h>
3
#include <sys/types.h>
4
#include <sys/stat.h>
5
#include "../useful.h"
6
///////////////////////////////////////////////////// TEST ///////////////////////////////////////////////////////\
7
8
TEST(ClockClass, AddTwoHours)
1
9
{
1
10
    Clock f(13,57);
1
11
    Clock g(23,59);
1
12
    Clock r = f+g;
1
13
    EXPECT_EQ(r.getString(), "13:56");
1
14
}
15
16
TEST(ClockClass, lessThen_Hours)
1
17
{
1
18
    Clock f(13,57);
1
19
    Clock g(23,59);
1
20
    EXPECT_EQ(f<g, true);
1
21
}
22
23
TEST(ClockClass, plus_operator)
1
24
{
1
25
    Clock f(13,57);
1
26
    f+=Clock("04:04");
1
27
    EXPECT_EQ(f.getString(),"18:01");
1
28
}
29
30
TEST(ClockClass, _operator)
1
31
{
1
32
    EXPECT_FALSE(Clock("04:04") == Clock("04:05"));
1
33
    EXPECT_FALSE(Clock("05:05") == Clock("04:05"));
1
34
    EXPECT_TRUE(Clock("05:05") == Clock("05:05"));
1
35
    EXPECT_FALSE(Clock("05:05") != Clock("05:05"));
1
36
    EXPECT_TRUE(Clock("04:05") != Clock("05:05"));
1
37
    EXPECT_TRUE(Clock("04:05") != Clock("04:04"));
1
38
    EXPECT_TRUE(Clock("04:05") > Clock("04:04"));
1
39
    EXPECT_FALSE(Clock("03:05") > Clock("04:04"));
1
40
    EXPECT_TRUE(Clock("04:05") >= Clock("04:04"));
1
41
    EXPECT_FALSE(Clock("04:05") <= Clock("04:04"));
1
42
    EXPECT_FALSE(Clock("05:05") <= Clock("04:05"));
1
43
    EXPECT_TRUE(Clock("03:05") <= Clock("04:05"));
1
44
    EXPECT_TRUE(Clock("04:05") <= Clock("04:06"));
1
45
    EXPECT_TRUE(Clock("04:05") < Clock("04:06"));
1
46
    EXPECT_TRUE(Clock("08:05") > Clock("04:06"));
1
47
1
48
    std::stringstream s;
1
49
    Clock f("00:00");
1
50
    s << f;
1
51
    EXPECT_STREQ("00:00", s.str().c_str());
1
52
1
53
    Clock g("20:00");
1
54
    f = g.getTime();
1
55
    g += Clock("23:43");
1
56
    EXPECT_STREQ("19:43", g.getString().c_str());
1
57
}
58
59
TEST(ClockClass, periodOfTime)
1
60
{
1
61
    Clock f(13,57);
1
62
    Clock g(22,22);
1
63
    Clock r = Clock::periodOfTime(f,g);
1
64
    EXPECT_EQ(r.getString(),"08:25");
1
65
    r = Clock::periodOfTime(g,f);
1
66
    EXPECT_EQ(r.getString(),"15:35");
1
67
}
68
69
TEST(ClockClass, from_to_second)
1
70
{
1
71
    Clock f;
1
72
    f.set(13,57);
1
73
    unsigned int sec = f.toSeconds();
1
74
    Clock g = Clock::fromSeconds(sec);
1
75
    EXPECT_EQ(f.getString(),g.getString());
1
76
}
77
78
TEST(ClockClass, stopwatch)
1
79
{
1
80
    Clock f;
1
81
    f.stopwatchStart();
1
82
    sleep(2);
1
83
    EXPECT_EQ(2,f.stopwatchStopAndGetResult());
1
84
}
85
86
TEST(JSON, getJSON)
1
87
{
1
88
    nlohmann::json test_JSON = useful_F_libs::getJson("http://cyniu88.no-ip.pl/test/json/on_lightning.json");
1
89
    auto testKey = test_JSON["success"].get<bool>();
1
90
1
91
    std::cout << " JSON JEST" << std::endl << test_JSON.dump(4) << std::endl;
1
92
1
93
    EXPECT_TRUE(testKey);
1
94
}
95
96
TEST(ClockClass, wrongSet)
1
97
{
1
98
    Clock f;
1
99
    EXPECT_ANY_THROW(f.set(99,99));
1
100
}
101
102
TEST(ClockClass, to_string_with_precision_TC)
1
103
{
1
104
    double d = 1.0/3.0;
1
105
    EXPECT_STREQ("0.33", to_string_with_precision(d,2).c_str() );
1
106
}
107
108
TEST(mkfifo_test, mkfifoFile)
1
109
{
1
110
    std::string path = "/mnt/ramdisk/FifoFile";
1
111
    std::string msg = "kokos";
1
112
    std::string returnString;
1
113
    int temp = mkfifo(path.c_str(),0666);
1
114
1
115
//    if ( temp == -1)
1
116
//        std::cout << "plik istnieje "<<strerror(errno)<< std::endl;
1
117
//    else if (temp == 0)
1
118
//        std::cout << "plik stworzony"<< std::endl;
1
119
//    else
1
120
//        FAIL();
1
121
1
122
//    useful_F_libs::write_to_mkfifo(path,msg);
1
123
1
124
//    returnString = useful_F_libs::read_from_mkfifo(path);
1
125
1
126
//    EXPECT_STREQ(returnString.c_str(), msg.c_str()) << "odczytano smieci";
1
127
    //TODO not
1
128
1
129
}
/home/cyniu/GIT/malina/iDom_server_OOP/libs/useful/usefull.cpp
1
#include "useful.h"
2
#include <sys/fcntl.h>
3
#include <unistd.h>
4
#include <sys/types.h>
5
#include <sys/stat.h>
6
#include <fcntl.h>
7
#ifndef IDOM
8
#include <curl/curl.h>
9
#endif
35
10
std::vector<std::string> split_string(const std::string& s, char separator ){
35
11
    std::vector<std::string> output;
35
12
    std::string::size_type prev_pos = 0, pos = 0;
35
13
70
14
    while((pos = s.find(separator, pos)) != std::string::npos)
35
15
    {
35
16
        std::string substring( s.substr(prev_pos, pos-prev_pos) );
35
17
        output.push_back(substring);
35
18
        prev_pos = ++pos;
35
19
    }
35
20
    try {
35
21
        output.push_back(s.substr(prev_pos, pos-prev_pos)); // Last word
35
22
    }
0
23
    catch (...){
0
24
0
25
    }
35
26
    return output;
35
27
}
28
286
29
std::string stateToString(STATE s){
0
30
    switch (s) {
13
31
    case STATE::OFF:        return "OFF";
6
32
    case STATE::ON:         return "ON";
6
33
    case STATE::PLAY:       return "PLAY";
0
34
    case STATE::PAUSE:      return "PAUSE";
0
35
    case STATE::STOP:       return "STOP";
7
36
    case STATE::ACTIVE:     return "ACTIVE";
11
37
    case STATE::DEACTIVE:   return "DEACTIVE";
0
38
    case STATE::WORKING:    return "WORKING";
0
39
    case STATE::DEFINE:     return "DEFINE";
200
40
    case STATE::UNDEFINE:   return "UNDEFINE";
23
41
    case STATE::LOCK:       return "LOCK";
7
42
    case STATE::UNLOCK:     return "UNLOCK";
0
43
    case STATE::EMPTY:      return "EMPTY";
0
44
    case STATE::FULL:       return "FULL";
0
45
    case STATE::SEND_OK:    return "SEND_OK";
0
46
    case STATE::SEND_NOK:   return "SEND_NOK";
13
47
    default:
13
48
        return "UNKNOWN";
0
49
    }
286
50
}
51
52
#ifndef IDOM
53
void useful_F_libs::write_to_mkfifo(const std::string& path, const std::string& msg)
0
54
{
0
55
    int fd = open(path.c_str(), O_WRONLY| O_NONBLOCK);
0
56
    write(fd, msg.c_str(), msg.size());
0
57
    close(fd);
0
58
}
59
60
std::string useful_F_libs::read_from_mkfifo(const std::string& path)
0
61
{
0
62
    char buf[10];
0
63
    /* open, read, and display the message from the FIFO */
0
64
    int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
0
65
    read(fd, buf, 10);
0
66
    close(fd);
0
67
    return (std::string(buf));
0
68
}
69
70
size_t useful_F_libs::WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
15
71
{
15
72
    ((std::string*)userp)->append((char*)contents, size * nmemb);
15
73
    return size * nmemb;
15
74
}
75
76
std::string useful_F_libs::find_tag(const std::string& temp)
8
77
{
8
78
    std::string value = "";
168
79
    for (unsigned int i = 0; i<temp.size();++i){
168
80
168
81
        if (temp.at(i) =='>')
8
82
        {  int z = i+1;
24
83
            while (temp.at(z)!='<')
16
84
            {
16
85
                value+= temp.at(z);
16
86
                ++z;
16
87
            }
8
88
            break;
8
89
        }
168
90
    }
8
91
    return value;
8
92
}
93
94
#ifndef BT_TEST
95
std::string useful_F_libs::httpPost(const std::string& url, int timeoutSeconds)
96
{
97
    CURL *curl;
98
    CURLcode res;
99
    std::string readBuffer;
100
    curl = curl_easy_init();
101
102
    if(curl) {
103
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeoutSeconds);
104
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
105
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, useful_F_libs::WriteCallback);
106
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
107
        res = curl_easy_perform(curl);
108
        /* Check for errors */
109
        if(res != CURLE_OK)
110
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
111
                    curl_easy_strerror(res));
112
113
        /* always cleanup */
114
        curl_easy_cleanup(curl);
115
    }
116
    curl_global_cleanup();
117
118
    return readBuffer;
119
}
120
121
std::string useful_F_libs::httpPost(const std::string& url)
122
{
123
    return useful_F_libs::httpPost(url, 10);
124
}
125
#endif
126
127
void useful_F_libs::downloadFile(const std::string& url, const std::string& path, int timeoutSeconds)
0
128
{
0
129
    CURL *curl;
0
130
    //CURLcode res;
0
131
0
132
    curl = curl_easy_init();
0
133
    if (curl) {
0
134
        FILE *fp = fopen(path.c_str(),"wb");
0
135
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeoutSeconds);
0
136
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
0
137
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
0
138
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
0
139
        //res = curl_easy_perform(curl);
0
140
        /* always cleanup */
0
141
        curl_easy_cleanup(curl);
0
142
        fclose(fp);
0
143
    }
0
144
}
145
3
146
std::string useful_F_libs::replaceAll(std::string str, const std::string& from, const std::string& to) {
3
147
    size_t start_pos = 0;
11
148
    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
8
149
        str.replace(start_pos, from.length(), to);
8
150
        start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
8
151
    }
3
152
    return str;
3
153
}
154
std::string useful_F_libs::removeHtmlTag(std::string &data)
2
155
{
2
156
    data = useful_F_libs::replaceAll(data,"</dl>","\n");
2
157
2
158
    //data = useful_F::replaceAll(data,"    "," ");
2
159
    bool copy = true;
2
160
    std::string plainString = "";
2
161
    std::stringstream convertStream;
2
162
2
163
    // remove all xml tags
2.88k
164
    for (unsigned int i=0; i < data.length(); i++)
2.87k
165
    {
2.87k
166
        convertStream << data[i];
2.87k
167
2.87k
168
        if(convertStream.str().compare("<") == 0) copy = false;
2.85k
169
        else if(convertStream.str().compare(">") == 0)
19
170
        {
19
171
            copy = true;
19
172
            convertStream.str(std::string());
19
173
            continue;
19
174
        }
2.87k
175
2.85k
176
        if(copy) plainString.append(convertStream.str());
2.85k
177
2.85k
178
        convertStream.str(std::string());
2.85k
179
    }
2
180
2
181
    return plainString;
2
182
}
183
184
nlohmann::json useful_F_libs::getJson(const std::string& url)
4
185
{
4
186
    std::string str = useful_F_libs::httpPost(url);
4
187
    nlohmann::json jj = nlohmann::json::parse( str);
4
188
4
189
    return jj;
4
190
}
191
#endif
/home/cyniu/GIT/malina/iDom_server_OOP/src/433MHz/RFLink/TEST/rflinkhandler_BT.cpp
1
#include <gtest/gtest.h>
2
3
#include "../rflinkhandler.h"
4
#include "test_data.h"
5
6
class RFLinkHandler_Class_fixture : public ::testing::Test
7
{
8
public:
9
    thread_data test_my_data;
10
    config test_server_set;
11
    iDomSTATUS test_status;
12
    RFLinkHandler* test_RFLink;
13
14
    void SetUp() final
3
15
    {
3
16
        test_server_set.TS_KEY = "key test";
3
17
        test_server_set.RFLinkBaudRate = "57600";
3
18
        test_server_set.RFLinkPort = "/dev/fakePortRS232";
3
19
        test_my_data.server_settings = &test_server_set;
3
20
        test_my_data.main_iDomStatus = &test_status;
3
21
        test_RFLink = new RFLinkHandler(&test_my_data);
3
22
    }
23
    void TearDown() final
3
24
    {
3
25
        delete test_RFLink;
3
26
    }
27
};
28
29
TEST_F(RFLinkHandler_Class_fixture, sendCommandAndWaitForReceive)
1
30
{
1
31
    test_RFLink->init();
1
32
    std::string k("msg_test;\n a=4:b=10;\n");
1
33
    SerialPi_set_recv_msg(k);
1
34
    std::string r = test_RFLink->sendCommandAndWaitForReceive("test command");
1
35
1
36
    EXPECT_STREQ(r.c_str(),"msg_test;");
1
37
    r = test_RFLink->sendCommandAndWaitForReceive("ok");
1
38
    EXPECT_STREQ(r.c_str()," a=4:b=10;");
1
39
}
40
41
TEST_F(RFLinkHandler_Class_fixture, port_does_not_exist)
1
42
{
1
43
    bool result =  test_RFLink->init();
1
44
    EXPECT_FALSE(result);
1
45
}
46
47
TEST_F(RFLinkHandler_Class_fixture, getValue)
1
48
{
1
49
    std::string m  = "20;90;Alecto V4;ID=557a;TEMP=0057;HUM=25;";
1
50
    EXPECT_STREQ(test_RFLink->getArgumentValueFromRFLinkMSG(m,"ID").c_str(),"557a");
1
51
    EXPECT_STREQ(test_RFLink->getArgumentValueFromRFLinkMSG(m,"TEMP").c_str(),"0057");
1
52
    EXPECT_THROW(test_RFLink->getArgumentValueFromRFLinkMSG(m,"test"),std::string);
1
53
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/433MHz/RFLink/rflinkhandler.cpp
1
#include <unistd.h>
2
3
#include "rflinkhandler.h"
4
#include "../../functions/functions.h"
5
6
std::mutex RFLinkHandler::sm_RFLink_MUTEX;
7
std::string RFLinkHandler::sm_RFLink_BUFOR;
8
9
10
RFLinkHandler::RFLinkHandler(thread_data *my_data):
11
    serial_RFLink(my_data->server_settings->RFLinkPort)
18
12
{
18
13
    this->my_data = my_data;
18
14
#ifdef BT_TEST
18
15
    std::cout << "RFLinkHandler::RFLinkHandler()"<<std::endl;
18
16
#endif
18
17
}
18
19
bool RFLinkHandler::init()
2
20
{
2
21
    if( access( my_data->server_settings->RFLinkPort.c_str(), F_OK ) != -1 )
0
22
    {
0
23
        serial_RFLink.begin( std::stoi(my_data->server_settings->RFLinkBaudRate));
0
24
#ifndef BT_TEST
25
        log_file_mutex.mutex_lock();
26
        log_file_cout << INFO <<"otwarcie portu RS232 RFLink " << my_data->server_settings->RFLinkPort << "  "
27
                      <<my_data->server_settings->RFLinkBaudRate<<std::endl;
28
        log_file_mutex.mutex_unlock();
29
#endif
0
30
        return true;
0
31
    }
2
32
    else
2
33
    {
2
34
#ifndef BT_TEST
35
        log_file_mutex.mutex_lock();
36
        log_file_cout << ERROR <<"brak portu RS232 RFLink " << my_data->server_settings->RFLinkPort<<std::endl;
37
        log_file_mutex.mutex_unlock();
38
#endif
2
39
        return false;
2
40
    }
2
41
}
42
43
void RFLinkHandler::flush()
0
44
{
0
45
    serial_RFLink.flush();
0
46
}
47
48
void RFLinkHandler::sendCommand(std::string cmd)
0
49
{
0
50
    std::lock_guard<std::mutex> m_lock(sm_RFLink_MUTEX);
0
51
    cmd.append("\n\r"); // add NL & CR
0
52
    serial_RFLink.print(cmd.c_str());
0
53
}
54
55
std::string RFLinkHandler::sendCommandAndWaitForReceive(std::string cmd)
2
56
{
2
57
    std::lock_guard<std::mutex> m_lock(sm_RFLink_MUTEX);
2
58
    cmd.append("\n\r"); // add NL & CR
2
59
    serial_RFLink.print(cmd.c_str());
2
60
    return internalReadFromRS232();
2
61
}
62
63
std::string RFLinkHandler::readFromRS232()
0
64
{
0
65
    std::lock_guard<std::mutex> m_lock(sm_RFLink_MUTEX);
0
66
    return internalReadFromRS232();
0
67
}
68
69
std::string RFLinkHandler::internalReadFromRS232()
2
70
{
2
71
    std::string buf;
2
72
2
73
    if(serial_RFLink.available() > 0){
2
74
        //puts("jest cos na rflinku");
21
75
        while (true){
21
76
21
77
            char b = serial_RFLink.read();
21
78
            if (b == '\n'){
2
79
                break;
2
80
            }
19
81
            buf += b;
19
82
        }
2
83
    }
2
84
    return buf;
2
85
}
86
87
std::string RFLinkHandler::getArgumentValueFromRFLinkMSG(const std::string& msg, const std::string& var)
50
88
{
50
89
    std::string id;
50
90
50
91
    int pos = msg.find(var+"=");
50
92
    if (pos == -1 ){
6
93
        throw "argument \""+var+"\" not found";
6
94
    }
44
95
    if (msg.at(0) != '2' || msg.at(1) != '0'){
1
96
        throw WRONG_FORMAT();
1
97
    }
44
98
#ifdef BT_TEST
43
99
    std::cout << "znaleziono " << var <<" na pozycji " << pos <<std::endl;
43
100
#endif
43
101
261
102
    for (int i = 1+pos+var.size();;++i ){
261
103
        char t = msg.at(i);
261
104
        if (t ==';'){
43
105
            break;
43
106
        }
218
107
        id += t;
218
108
    }
43
109
    return id;
44
110
44
111
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/LCD_c/test/lcd_c_stub.cpp
1
#include <iostream>
2
#include "../lcd_c.h"
3
1
4
void LCD_c::set_print_song_state(int i){
1
5
    std::cout << "LCD_c::set_print_song_state(int i)" << i <<std::endl;
1
6
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/RADIO_433_eq/radio_433_eq.cpp
1
#include <iostream>
2
#include <fstream>
3
#include <sstream>
4
#include "radio_433_eq.h"
5
6
RADIO_SWITCH::RADIO_SWITCH(thread_data *my_data, const RADIO_EQ_CONFIG &cfg, RADIO_EQ_TYPE type):
7
    main433MHz(my_data)
272
8
{
272
9
    puts("RADIO_SWITCH::RADIO_SWITCH()");
272
10
    RADIO_EQ::m_my_data = my_data;
272
11
    RADIO_EQ::m_type = type;
272
12
    RADIO_EQ::m_config = cfg;
272
13
}
14
15
RADIO_SWITCH::~RADIO_SWITCH()
272
16
{
272
17
    puts("RADIO_SWITCH::~RADIO_SWITCH()");
272
18
}
19
20
void RADIO_SWITCH::on()
3
21
{
3
22
    main433MHz.sendCode(RADIO_EQ::m_config.onCode);
3
23
    m_state = STATE::ON;
3
24
    RADIO_EQ::m_my_data->main_iDomStatus->setObjectState(RADIO_EQ::m_config.name, STATE::ON);
3
25
}
26
27
void RADIO_SWITCH::off()
3
28
{
3
29
    main433MHz.sendCode(RADIO_EQ::m_config.offCode);
3
30
    m_state = STATE::OFF;
3
31
    RADIO_EQ::m_my_data->main_iDomStatus->setObjectState(RADIO_EQ::m_config.name,STATE::OFF);
3
32
}
33
34
void RADIO_SWITCH::onFor15sec()
0
35
{
0
36
    main433MHz.sendCode(RADIO_EQ::m_config.on15sec);
0
37
    m_state = STATE::WORKING;
0
38
}
39
40
void RADIO_SWITCH::onSunrise()
0
41
{
0
42
    if(m_sunrise == STATE::ON ){
0
43
        on();
0
44
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " ON due to sunrise");
0
45
    }
0
46
    else if(m_sunrise == STATE::OFF){
0
47
        off();
0
48
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " OFF due to sunrise");
0
49
    }
0
50
}
51
52
void RADIO_SWITCH::onSunset()
1
53
{
1
54
    if(m_sunset == STATE::ON ){
0
55
        on();
0
56
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " ON due to sunset");
0
57
    }
1
58
    else if(m_sunset == STATE::OFF){
0
59
        off();
0
60
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " OFF due to sunset");
0
61
    }
1
62
}
63
64
void RADIO_SWITCH::onLockHome()
5
65
{
5
66
     std::cout << " w configu jest " << m_config.lock << std::endl;
5
67
    if (m_config.lock == "ON")
0
68
    {
0
69
        on();
0
70
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " ON due to 433MHz button pressed");
0
71
    }
5
72
    else if(m_config.lock == "OFF")
1
73
    {
1
74
        off();
1
75
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " OFF due to 433MHz button pressed");
1
76
    }
5
77
}
78
79
void RADIO_SWITCH::onUnlockHome()
5
80
{
5
81
    if (m_config.unlock == "ON")
1
82
    {
1
83
        on();
1
84
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " ON due to 433MHz button pressed");
1
85
    }
4
86
    else if (m_config.unlock == "OFF")
0
87
    {
0
88
        off();
0
89
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " OFF due to 433MHz button pressed");
0
90
    }
5
91
}
92
93
STATE RADIO_SWITCH::getState()
170
94
{
170
95
    return m_state;
170
96
}
97
98
std::string RADIO_SWITCH::getName()
190
99
{
190
100
    return RADIO_EQ::m_config.name;
190
101
}
102
103
std::string RADIO_SWITCH::getID()
81
104
{
81
105
    return RADIO_EQ::m_config.ID;
81
106
}
107
108
void RADIO_SWITCH::setCode(RADIO_EQ_CONFIG cfg)
268
109
{
268
110
    RADIO_EQ::m_config.onCode = cfg.onCode;
268
111
    RADIO_EQ::m_config.offCode = cfg.offCode;
268
112
    RADIO_EQ::m_config.on15sec = cfg.on15sec;
268
113
    RADIO_EQ::m_config.type = cfg.type;
268
114
268
115
    if(cfg.sunset == "on"){
0
116
        m_sunset = STATE::ON;
0
117
    }
268
118
    if(cfg.sunset == "off"){
0
119
        m_sunset = STATE::OFF;
0
120
    }
268
121
    if(cfg.sunrise == "on"){
0
122
        m_sunrise = STATE::ON;
0
123
    }
268
124
    if(cfg.sunrise == "off"){
0
125
        m_sunrise = STATE::OFF;
0
126
    }
268
127
}
128
129
RADIO_EQ_CONTAINER::RADIO_EQ_CONTAINER(thread_data *my_data)
56
130
{
56
131
    puts("RADIO_EQ_CONTAINER::RADIO_EQ_CONTAINER()");
56
132
    this->my_data = my_data;
56
133
}
134
135
RADIO_EQ_CONTAINER::~RADIO_EQ_CONTAINER()
56
136
{
431
137
    for(auto it = m_radioEqMap.begin(); it != m_radioEqMap.end(); ++it) {
375
138
        delete it->second;
375
139
    }
56
140
    puts("RADIO_EQ_CONTAINER::~RADIO_EQ_CONTAINER()");
56
141
}
142
143
void RADIO_EQ_CONTAINER::addRadioEq( RADIO_EQ_CONFIG cfg, RADIO_EQ_TYPE type)
378
144
{
378
145
    switch (type) {
270
146
    case RADIO_EQ_TYPE::SWITCH:
270
147
        m_radioEqMap.insert(std::make_pair(cfg.name, new RADIO_SWITCH(my_data, cfg, RADIO_EQ_TYPE::SWITCH)  )    );
270
148
        break;
54
149
    case RADIO_EQ_TYPE::BUTTON:
54
150
        m_radioEqMap.insert(std::make_pair(cfg.name, new RADIO_BUTTON(my_data, cfg, RADIO_EQ_TYPE::BUTTON)  )    );
54
151
        break;
53
152
    case RADIO_EQ_TYPE::WEATHER_S:
53
153
        m_radioEqMap.insert(std::make_pair(cfg.name, new RADIO_WEATHER_STATION(my_data, cfg, RADIO_EQ_TYPE::WEATHER_S) ) );
53
154
        break;
1
155
    default:
1
156
        break;
378
157
    }
378
158
}
159
160
void RADIO_EQ_CONTAINER::addRadioEq(RADIO_EQ_CONFIG cfg, const std::string&  type)
4
161
{
4
162
    RADIO_EQ_TYPE ret = RADIO_EQ_TYPE::NONE;
4
163
    if(type == "SWITCH") ret = RADIO_EQ_TYPE::SWITCH;
2
164
    else if(type == "BUTTON") ret = RADIO_EQ_TYPE::BUTTON;
2
165
    else if(type == "WEATHER") ret = RADIO_EQ_TYPE::WEATHER_S;
2
166
    else if(type == "PIR") ret = RADIO_EQ_TYPE::PIR;
1
167
    else if(type == "GATE") ret = RADIO_EQ_TYPE::GATE;
1
168
    else throw WRONG_FORMAT();
3
169
    std::cout << " id ma : " << cfg.ID << std::endl;
3
170
    std::stoi(cfg.ID); //check ID is number
3
171
    addRadioEq(cfg,ret);
3
172
}
173
174
void RADIO_EQ_CONTAINER::deleteRadioEq(const std::string& name)
2
175
{
2
176
    delete m_radioEqMap[name];
2
177
    m_radioEqMap.erase(name);
2
178
    saveConfig(my_data->server_settings->radio433MHzConfigFile);
2
179
}
180
181
RADIO_EQ* RADIO_EQ_CONTAINER::getEqPointer(std::string name)
287
182
{
287
183
    auto m = m_radioEqMap.find(name);
287
184
    if (m != m_radioEqMap.end()){
286
185
        return (m->second);
286
186
    }
287
187
    else
1
188
    {
1
189
        throw std::string("433MHz equipment not found "+name);
1
190
    }
287
191
}
192
193
std::vector<RADIO_SWITCH*> RADIO_EQ_CONTAINER::getSwitchPointerVector()
50
194
{
50
195
    std::vector<RADIO_SWITCH*> switchVector;
50
196
346
197
    for (auto it : m_radioEqMap){
346
198
        if (it.second->getType() == RADIO_EQ_TYPE::SWITCH){
246
199
            switchVector.push_back(static_cast<RADIO_SWITCH*>(it.second));
246
200
        }
346
201
    }
50
202
    return switchVector;
50
203
}
204
205
std::vector<RADIO_BUTTON *> RADIO_EQ_CONTAINER::getButtonPointerVector()
68
206
{
68
207
    std::vector<RADIO_BUTTON*> buttonVector;
68
208
474
209
    for (auto it : m_radioEqMap){
474
210
        if (it.second->getType() == RADIO_EQ_TYPE::BUTTON){
68
211
            buttonVector.push_back(static_cast<RADIO_BUTTON*>(it.second));
68
212
        }
474
213
    }
68
214
    return buttonVector;
68
215
}
216
217
std::vector<RADIO_WEATHER_STATION *> RADIO_EQ_CONTAINER::getWeather_StationPtrVector()
14
218
{
14
219
    std::vector<RADIO_WEATHER_STATION*> weatherStVe;
98
220
    for (auto it : m_radioEqMap){
98
221
        if (it.second->getType() == RADIO_EQ_TYPE::WEATHER_S){
14
222
            weatherStVe.push_back(static_cast<RADIO_WEATHER_STATION*>(it.second));
14
223
        }
98
224
    }
14
225
    return weatherStVe;
14
226
}
227
228
std::string RADIO_EQ_CONTAINER::listAllName()
17
229
{
17
230
    std::string allName;
17
231
132
232
    for(auto it = m_radioEqMap.begin(); it != m_radioEqMap.end(); ++it) {
115
233
        allName.append(it->first);
115
234
        allName.append("\t ID: ");
115
235
        allName.append( it->second->getID()  );
115
236
        allName.append("\t state: ");
115
237
        allName.append(stateToString(it->second->getState()  ));
115
238
        allName.append("\n");
115
239
    }
17
240
17
241
    return allName;
17
242
}
243
244
bool RADIO_EQ_CONTAINER::nameExist(const std::string& name)
10
245
{
10
246
    bool exist = false;
10
247
    if(m_radioEqMap.find(name) != m_radioEqMap.end())
3
248
    {
3
249
        exist = true;
3
250
    }
10
251
    return exist;
10
252
}
253
254
void RADIO_EQ_CONTAINER::loadConfig(const std::string& filePath)
54
255
{
54
256
    std::ifstream myfile (filePath);
54
257
    if (myfile.is_open())
54
258
    {
54
259
        nlohmann::json j;
54
260
        myfile >> j;
54
261
54
262
        RADIO_EQ_CONFIG cfg;
54
263
54
264
        try
54
265
        {
54
266
            nlohmann::json switchJson = j.at("SWITCH");
322
267
            for (nlohmann::json::iterator it = switchJson.begin(); it != switchJson.end(); ++it)
268
268
            {
268
269
                nlohmann::json switchJson =  it.value();
268
270
                cfg.name = switchJson.at("name").get<std::string>();
268
271
                cfg.ID   = switchJson.at("id").get<std::string>();
268
272
                cfg.offCode = switchJson.at("OFF").get<std::string>();
268
273
                cfg.onCode  = switchJson.at("ON").get<std::string>();
268
274
                cfg.on15sec = switchJson.at("on15sec").get<std::string>();
268
275
                cfg.sunrise = switchJson.at("sunrise").get<std::string>();
268
276
                cfg.sunset  = switchJson.at("sunset").get<std::string>();
268
277
                cfg.lock    = switchJson.at("lock").get<std::string>();
268
278
                cfg.unlock  = switchJson.at("unlock").get<std::string>();
268
279
                cfg.type    = switchJson.at("type").get<std::string>();
268
280
                addRadioEq(cfg,RADIO_EQ_TYPE::SWITCH);
268
281
                dynamic_cast<RADIO_SWITCH*>(getEqPointer(cfg.name))->setCode(cfg);
268
282
            }
54
283
        }
54
284
        catch(...)
0
285
        {
0
286
#ifndef BT_TEST
287
        log_file_mutex.mutex_lock();
288
        log_file_cout << DEBUG << "no SWITCH equipment in config" <<   std::endl;
289
        log_file_mutex.mutex_unlock();
290
#else
0
291
            std::cout << "no SWITCH equipment in config" <<std::endl;
0
292
#endif
0
293
        }
54
294
54
295
        try
54
296
        {
54
297
            nlohmann::json buttonJson = j.at("BUTTON");
108
298
            for (nlohmann::json::iterator it = buttonJson.begin(); it != buttonJson.end(); ++it)
54
299
            {
54
300
                nlohmann::json buttonJson =  it.value();
54
301
                cfg.name = buttonJson.at("name").get<std::string>();
54
302
                cfg.ID   = buttonJson.at("id").get<std::string>();
54
303
                cfg.offCode = buttonJson.at("OFF").get<std::string>();
54
304
                cfg.onCode  = buttonJson.at("ON").get<std::string>();
54
305
                cfg.type    = buttonJson.at("type").get<std::string>();
54
306
                addRadioEq(cfg,RADIO_EQ_TYPE::BUTTON);
54
307
            }
54
308
        }
54
309
        catch(...)
0
310
        {
0
311
#ifndef BT_TEST
312
            log_file_mutex.mutex_lock();
313
            log_file_cout << DEBUG << "no BUTTONs equipment in config" <<   std::endl;
314
            log_file_mutex.mutex_unlock();
315
#else
0
316
            std::cout << "no BUTTONs equipment in config"  <<std::endl;
0
317
#endif
0
318
        }
54
319
54
320
        try
54
321
        {
54
322
            nlohmann::json weatherJson= j.at("WEATHER");
107
323
            for (nlohmann::json::iterator it = weatherJson.begin(); it != weatherJson.end(); ++it)
53
324
            {
53
325
                nlohmann::json weatherJson =  it.value();
53
326
                cfg.name = weatherJson.at("name").get<std::string>();
53
327
                cfg.ID   = weatherJson.at("id").get<std::string>();
53
328
                cfg.type    = weatherJson.at("type").get<std::string>();
53
329
                addRadioEq(cfg,RADIO_EQ_TYPE::WEATHER_S);
53
330
            }
54
331
        }
54
332
        catch(...)
1
333
        {
1
334
#ifndef BT_TEST
335
            log_file_mutex.mutex_lock();
336
            log_file_cout << DEBUG << "no WEATHER STAIONs equipment in config" <<   std::endl;
337
            log_file_mutex.mutex_unlock();
338
#else
1
339
            std::cout << "no  WEATHER STAIONs  equipment in config"  <<std::endl;
1
340
#endif
1
341
        }
54
342
54
343
        myfile.close();
54
344
    }
0
345
    else std::cout << "Unable to open file";
54
346
}
347
348
void RADIO_EQ_CONTAINER::saveConfig(const std::string& filePath)
6
349
{
6
350
    nlohmann::json switchJson;
6
351
    nlohmann::json buttonJson;
6
352
    nlohmann::json weatherJson;
6
353
6
354
    std::vector<RADIO_SWITCH*> vSwitch = getSwitchPointerVector();
6
355
    for(auto s : vSwitch)
30
356
    {
30
357
        switchJson[s->getName()] = s->m_config.getJson();
30
358
    }
6
359
6
360
    std::vector<RADIO_BUTTON*> vButton = getButtonPointerVector();
6
361
    for (auto s : vButton)
6
362
    {
6
363
        buttonJson[s->getName()] = s->m_config.getJson();
6
364
    }
6
365
6
366
    std::vector<RADIO_WEATHER_STATION *> vWeather = getWeather_StationPtrVector();
6
367
    for(auto s : vWeather)
6
368
    {
6
369
        weatherJson[s->getName()] = s->m_config.getJson();
6
370
    }
6
371
6
372
    m_configJson["SWITCH"] = switchJson;
6
373
    m_configJson["BUTTON"] = buttonJson;
6
374
    m_configJson["WEATHER"] = weatherJson ;
6
375
    // write prettified JSON to another file
6
376
    std::ofstream o(filePath);
6
377
    o << std::setw(4) << m_configJson << std::endl;
6
378
}
379
380
RADIO_EQ::RADIO_EQ()
379
381
{
379
382
    this->m_my_data = std::nullptr_t();
379
383
    puts("RADIO_EQ::RADIO_EQ()");
379
384
}
385
386
RADIO_EQ::~RADIO_EQ()
379
387
{
379
388
    puts("RADIO_EQ::~RADIO_EQ()");
379
389
}
390
391
RADIO_EQ_TYPE RADIO_EQ::getType()
919
392
{
919
393
    return m_type;
919
394
}
395
396
RADIO_WEATHER_STATION::RADIO_WEATHER_STATION(thread_data *my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type)
53
397
{
53
398
    puts("RADIO_WEATHER_STATION::RADIO_WEATHER_STATION()");
53
399
    RADIO_EQ::m_my_data = my_data;
53
400
    RADIO_EQ::m_type = type;
53
401
    RADIO_EQ::m_config  = cfg;
53
402
}
403
404
RADIO_WEATHER_STATION::~RADIO_WEATHER_STATION()
53
405
{
53
406
    puts("RADIO_WEATHER_STATION::~RADIO_WEATHER_STATION()");
53
407
}
408
409
STATE RADIO_WEATHER_STATION::getState()
17
410
{
17
411
    return m_state;
17
412
}
413
414
std::string RADIO_WEATHER_STATION::getName()
6
415
{
6
416
    return RADIO_EQ::m_config.name;
6
417
}
418
419
std::string RADIO_WEATHER_STATION::getID()
26
420
{
26
421
    return RADIO_EQ::m_config.ID;
26
422
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/RADIO_433_eq/radio_433_eq.h
1
#ifndef RADIO_SWITCH_H
2
#define RADIO_SWITCH_H
3
#include <gtest/gtest.h>
4
#include <gmock/gmock.h>
5
#include <map>
6
#include "../iDomStatus/idomstatus.h"
7
#include "../433MHz/RFLink/rflinkhandler.h"
8
9
#include "../433MHz/rc_433mhz.h"
10
#include "json.hpp"
11
12
struct WEATHER_STRUCT{
13
private:
14
    unsigned long int m_counter = 0;
15
protected:
16
    unsigned int m_humidity = 0;
17
    double m_temperature = 0.0;
18
    unsigned int m_barometricPressure = 0;
19
public:
20
    unsigned int getHumidity(){ return m_humidity; }
21
    double getTemperature(){ return m_temperature; }
22
    unsigned int getBarometricPressure(){ return m_barometricPressure; }
23
    std::string getDataString(){
24
        return "data: "+std::to_string(m_counter)+"\n"+"Humidity=" + std::to_string(getHumidity()) +"%\n"+
25
                "temperature= " + to_string_with_precision(getTemperature()) + "c\n"+
26
                "Pressure= " + std::to_string(getBarometricPressure())+ "kPa\n";
27
    }
28
29
    void putData(std::string data){
30
        std::string tempStr;
31
        int t = 0;
32
        ++m_counter;
33
        try{
34
            m_humidity = std::stoi( RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "HUM") );
35
        }
36
        catch (...){  }
37
        try{
38
            tempStr =  RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "TEMP");
39
            std::stringstream ss;
40
            ss << std::hex << tempStr.substr(tempStr.size()-3,tempStr.size());
41
            ss >> t;
42
            m_temperature = t / 10.0;
43
            if(tempStr.at(0) == '8'){
44
                m_temperature *= -1.0;
45
            }
46
        }
47
        catch (...){  }
48
        //std::cout << "DUPA:  "<<data<<" temp=" << m_temperature<< " hum="<<m_humidity<< std::endl;
49
    }
50
};
51
52
enum class RADIO_EQ_TYPE{
53
    SWITCH = 1,
54
    PIR,
55
    GATE,
56
    BUTTON,
57
    WEATHER_S,
58
    NONE
59
};
60
struct RADIO_EQ_CONFIG{
61
    std::string name = "NULL";
62
    std::string ID   = "NULL";
63
    std::string type = "NULL";
64
    std::string onCode  = "NULL";
65
    std::string offCode = "NULL";
66
    std::string on15sec = "NULL";
67
    std::string sunrise = "NULL";
68
    std::string sunset  = "NULL";
69
    std::string lock   = "NULL";
70
    std::string unlock = "NULL";
71
    void set(std::string name,
72
             std::string ID,
73
             std::string type,
74
             std::string onCode,
75
             std::string offCode,
76
             std::string on15sec,
77
             std::string sunrise,
78
             std::string sunset,
79
             std::string lock,
80
             std::string unlock){
81
        this->name = name;
82
        this->ID   = ID;
83
        this->type = type;
84
        this->onCode  = onCode;
85
        this->offCode = offCode;
86
        this->on15sec = on15sec;
87
        this->sunrise = sunrise;
88
        this->sunset  = sunset;
89
        this->lock   = lock;
90
        this->unlock = unlock;
91
    }
92
42
93
    nlohmann::json getJson(){
42
94
        nlohmann::json jj;
42
95
        jj["name"]  = name;
42
96
        jj["id"]    = ID;
42
97
        jj["type"]  = type;
42
98
        jj["ON"]    = onCode;
42
99
        jj["OFF"]   = offCode;
42
100
        jj["on15sec"] = on15sec;
42
101
        jj["sunrise"] = sunrise;
42
102
        jj["sunset"]  = sunset;
42
103
        jj["lock"]   = lock;
42
104
        jj["unlock"] = unlock;
42
105
        return jj;
42
106
    }
107
};
108
109
class RADIO_EQ{
110
public:
111
    RADIO_EQ();
112
    virtual ~RADIO_EQ();
113
    virtual STATE getState() = 0;
114
    virtual std::string getName() = 0;
115
    virtual std::string getID() = 0;
116
    virtual RADIO_EQ_TYPE getType();
117
protected:
118
    thread_data *m_my_data;
119
    RADIO_EQ_TYPE m_type;
120
public:
121
    RADIO_EQ_CONFIG m_config;
122
};
123
class RADIO_WEATHER_STATION: public RADIO_EQ
124
{
125
    STATE m_state = STATE::UNDEFINE;
126
127
public:
128
    RADIO_WEATHER_STATION(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
129
    ~RADIO_WEATHER_STATION();
130
    STATE getState();
131
    std::string getName();
132
    std::string getID();
133
    // data
134
    WEATHER_STRUCT data;
135
};
136
class RADIO_BUTTON: public RADIO_EQ
137
{
138
    STATE m_state = STATE::UNDEFINE;
139
140
public:
141
    RADIO_BUTTON(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
142
    ~RADIO_BUTTON();
143
    STATE getState();
144
    void setState(STATE s);
145
    std::string getName();
146
    std::string getID();
147
};
148
149
class RADIO_SWITCH: public RADIO_EQ
150
{
151
    RC_433MHz main433MHz;
152
    STATE m_state = STATE::UNDEFINE;
153
public:
154
    RADIO_SWITCH(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
155
    ~RADIO_SWITCH();
156
    void on();
157
    void off();
158
    void onFor15sec();
159
    void onSunrise();
160
    void onSunset();
161
    void onLockHome();
162
    void onUnlockHome();
163
    STATE getState();
164
    std::string getName();
165
    std::string getID();
166
    void setCode(RADIO_EQ_CONFIG cfg);
167
    STATE m_sunrise = STATE::UNDEFINE;
168
    STATE m_sunset  = STATE::UNDEFINE;
169
};
170
171
class RADIO_EQ_CONTAINER
172
{
173
    std::map <std::string, RADIO_EQ* > m_radioEqMap;
174
    thread_data * my_data;
175
    nlohmann::json m_configJson;
176
public:
177
    RADIO_EQ_CONTAINER(thread_data * my_data);
178
    virtual ~RADIO_EQ_CONTAINER();
179
    void addRadioEq(RADIO_EQ_CONFIG cfg, RADIO_EQ_TYPE type);    
180
    void addRadioEq(RADIO_EQ_CONFIG cfg, const std::string& type);
181
    void deleteRadioEq(const std::string &name);
182
    virtual RADIO_EQ* getEqPointer(std::string name);
183
    std::vector<RADIO_SWITCH*> getSwitchPointerVector();
184
    std::vector<RADIO_BUTTON*> getButtonPointerVector();
185
    std::vector<RADIO_WEATHER_STATION *> getWeather_StationPtrVector();
186
    std::string listAllName();
187
    bool nameExist(const std::string &name);
188
    void loadConfig(const std::string &filePath);
189
    void saveConfig(const std::string &filePath);
190
};
191
192
class RADIO_EQ_CONTAINER_STUB : public RADIO_EQ_CONTAINER
193
{
194
    thread_data * k;
195
public:
196
    RADIO_EQ_CONTAINER_STUB(thread_data * k):RADIO_EQ_CONTAINER(k){this->k = k;}
197
198
    virtual ~RADIO_EQ_CONTAINER_STUB(){puts("~RADIO_EQ_CONTAINER_STUB()");}
199
    MOCK_METHOD1(getEqPointer, RADIO_EQ*(std::string name));
200
};
201
202
#endif // RADIO_SWITCH_H
/home/cyniu/GIT/malina/iDom_server_OOP/src/RADIO_433_eq/radio_button.cpp
1
#include "radio_433_eq.h"
2
/*
3
 * Najpierw możliwe do uzyskania funkcje załączania
4
5
    Załączenie chwilowe (momentary) - przekaźnik jest załączony tak długo jak długo naciskany jest klawisz pilota - nadawany kod
6
    Przełącznik (toggle) - przekaźnik jest załączany /wyłączany przy kolejnych naciśnięciach tego samego klawisza - nadajemy ten sam kod
7
    Włącz/wyłącz (latched) - przekaźnik jest załączany jednym kodem a wyłączany innym
8
    Włącznik czasowy 5 sek - po naciśnięciu pilota następuje załączenie przekaźnika na czas 5 sek
9
    Włącznik czasowy 10 sek - załączenie na czas 10 sek
10
    Włącznik czasowy 15 sek - załączenie na czas 15 sek
11
12
Programowanie
13
Niby opisane jest to na stronach dostawców - ale nie do końca - więc pełen opis programowania. Zalecane rozpoczęcie od punktu 8 - KASOWANIE
14
15
    Załączenie chwilowe (momentary) - naciskamy 1x przycisk programowania (potwierdzenie naciśnięcia krótkim błyskiem LED). LED po chwili włącza się na stałe na 8-10 sek. W tym czasie układ gotowy jest na przyjęcie nowego kodu. Wysłany kod zapamiętany jest w pamięci a potwierdzeniem tego jest podwójne "mrugnięcie" LEDa. LED gaśnie . Koniec procedury.
16
    Przełącznik (toggle) - naciskamy 2 x przycisk programowania. Dalej jak w pkt. 1
17
    Włącz/wyłącz (latched) - naciskamy 3 x przycisk programowania (potwierdzenie naciśnięcia krótkim błyskiem LED). LED po chwili włącza się na stałe na 8-10 sek. W tym czasie układ gotowy jest na przyjęcie nowego kodu. Wysłany kod zapamiętany jest w pamięci a potwierdzeniem tego jest podwójne "mrugnięcie" LEDa. LED pozostaje włączony Układ czeka na odbiór drugiego kodu. Po jego wysłaniu jest znowu podwójne "mrugnięcie" LEDa. LED gaśnie. Koniec procedury.
18
    Włącznik czasowy 5 sek - naciskamy 4 x przycisk programowania. Dalej jak w pkt. 1
19
    Włącznik czasowy 10 sek - naciskamy 5 x przycisk programowania. Dalej jak w pkt. 1
20
    Włącznik czasowy 15 sek - naciskamy 6 x przycisk programowania. Dalej jak w pkt. 1
21
    Włącznik czasowy 15 sek - naciskamy 7 x przycisk programowania. Dalej jak w pkt. 1
22
     KASOWANIE - usuwanie z pamięci wszystkich kodów. Nacisnąć 8 x przycisk  . Każde naciśniecie sygnalizowane jest błyśnięciem. Po 8 naciśnięciu następują trzy mignięcia i pamięć kodów jest wyzerowana. Można też skasować pamięć naciskając przycisk raz przez ok 8 sek . Po puszczeniu przycisku LED zapali się na ok 3-4 sek i zgaśnie. Efekt działania ten sam.
23
24
Wszystkie te funkcje działają równolegle bo układ może zapamiętać do 50 kodów! Dodatkowo w trybie włącznika czasowego można skrócić czas załączenia poprzez wysłanie kodu WYŁĄCZ z wcześniej ustawionej funkcji latched.
25
 */
26
RADIO_BUTTON::RADIO_BUTTON(thread_data *my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type)
54
27
{
54
28
    puts("RADIO_BUTTON::RADIO_BUTTON()");
54
29
    RADIO_EQ::m_my_data = my_data;
54
30
    RADIO_EQ::m_type = type;
54
31
    RADIO_EQ::m_config = cfg;
54
32
}
33
34
RADIO_BUTTON::~RADIO_BUTTON()
54
35
{
54
36
    puts("RADIO_BUTTON::~RADIO_BUTTON()");
54
37
}
38
39
STATE RADIO_BUTTON::getState()
17
40
{
17
41
    return m_state;
17
42
}
43
44
void RADIO_BUTTON::setState(STATE s)
6
45
{
6
46
    m_state = s;
6
47
}
48
49
std::string RADIO_BUTTON::getName()
7
50
{
7
51
    return RADIO_EQ::m_config.name;
7
52
}
53
54
std::string RADIO_BUTTON::getID()
29
55
{
29
56
    return RADIO_EQ::m_config.ID;
29
57
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/RADIO_433_eq/test/../../iDomTools/test/../../RADIO_433_eq/radio_433_eq.h
1
#ifndef RADIO_SWITCH_H
2
#define RADIO_SWITCH_H
3
#include <gtest/gtest.h>
4
#include <gmock/gmock.h>
5
#include <map>
6
#include "../iDomStatus/idomstatus.h"
7
#include "../433MHz/RFLink/rflinkhandler.h"
8
9
#include "../433MHz/rc_433mhz.h"
10
#include "json.hpp"
11
12
struct WEATHER_STRUCT{
13
private:
14
    unsigned long int m_counter = 0;
15
protected:
16
    unsigned int m_humidity = 0;
17
    double m_temperature = 0.0;
18
    unsigned int m_barometricPressure = 0;
19
public:
20
    unsigned int getHumidity(){ return m_humidity; }
5
21
    double getTemperature(){ return m_temperature; }
22
    unsigned int getBarometricPressure(){ return m_barometricPressure; }
23
    std::string getDataString(){
24
        return "data: "+std::to_string(m_counter)+"\n"+"Humidity=" + std::to_string(getHumidity()) +"%\n"+
25
                "temperature= " + to_string_with_precision(getTemperature()) + "c\n"+
26
                "Pressure= " + std::to_string(getBarometricPressure())+ "kPa\n";
27
    }
28
5
29
    void putData(std::string data){
5
30
        std::string tempStr;
5
31
        int t = 0;
5
32
        ++m_counter;
5
33
        try{
5
34
            m_humidity = std::stoi( RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "HUM") );
5
35
        }
4
36
        catch (...){  }
5
37
        try{
5
38
            tempStr =  RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "TEMP");
5
39
            std::stringstream ss;
5
40
            ss << std::hex << tempStr.substr(tempStr.size()-3,tempStr.size());
5
41
            ss >> t;
5
42
            m_temperature = t / 10.0;
5
43
            if(tempStr.at(0) == '8'){
2
44
                m_temperature *= -1.0;
2
45
            }
5
46
        }
1
47
        catch (...){  }
5
48
        //std::cout << "DUPA:  "<<data<<" temp=" << m_temperature<< " hum="<<m_humidity<< std::endl;
5
49
    }
50
};
51
52
enum class RADIO_EQ_TYPE{
53
    SWITCH = 1,
54
    PIR,
55
    GATE,
56
    BUTTON,
57
    WEATHER_S,
58
    NONE
59
};
60
struct RADIO_EQ_CONFIG{
61
    std::string name = "NULL";
62
    std::string ID   = "NULL";
63
    std::string type = "NULL";
64
    std::string onCode  = "NULL";
65
    std::string offCode = "NULL";
66
    std::string on15sec = "NULL";
67
    std::string sunrise = "NULL";
68
    std::string sunset  = "NULL";
69
    std::string lock   = "NULL";
70
    std::string unlock = "NULL";
71
    void set(std::string name,
72
             std::string ID,
73
             std::string type,
74
             std::string onCode,
75
             std::string offCode,
76
             std::string on15sec,
77
             std::string sunrise,
78
             std::string sunset,
79
             std::string lock,
80
             std::string unlock){
81
        this->name = name;
82
        this->ID   = ID;
83
        this->type = type;
84
        this->onCode  = onCode;
85
        this->offCode = offCode;
86
        this->on15sec = on15sec;
87
        this->sunrise = sunrise;
88
        this->sunset  = sunset;
89
        this->lock   = lock;
90
        this->unlock = unlock;
91
    }
92
93
    nlohmann::json getJson(){
94
        nlohmann::json jj;
95
        jj["name"]  = name;
96
        jj["id"]    = ID;
97
        jj["type"]  = type;
98
        jj["ON"]    = onCode;
99
        jj["OFF"]   = offCode;
100
        jj["on15sec"] = on15sec;
101
        jj["sunrise"] = sunrise;
102
        jj["sunset"]  = sunset;
103
        jj["lock"]   = lock;
104
        jj["unlock"] = unlock;
105
        return jj;
106
    }
107
};
108
109
class RADIO_EQ{
110
public:
111
    RADIO_EQ();
112
    virtual ~RADIO_EQ();
113
    virtual STATE getState() = 0;
114
    virtual std::string getName() = 0;
115
    virtual std::string getID() = 0;
116
    virtual RADIO_EQ_TYPE getType();
117
protected:
118
    thread_data *m_my_data;
119
    RADIO_EQ_TYPE m_type;
120
public:
121
    RADIO_EQ_CONFIG m_config;
122
};
123
class RADIO_WEATHER_STATION: public RADIO_EQ
124
{
125
    STATE m_state = STATE::UNDEFINE;
126
127
public:
128
    RADIO_WEATHER_STATION(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
129
    ~RADIO_WEATHER_STATION();
130
    STATE getState();
131
    std::string getName();
132
    std::string getID();
133
    // data
134
    WEATHER_STRUCT data;
135
};
136
class RADIO_BUTTON: public RADIO_EQ
137
{
138
    STATE m_state = STATE::UNDEFINE;
139
140
public:
141
    RADIO_BUTTON(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
142
    ~RADIO_BUTTON();
143
    STATE getState();
144
    void setState(STATE s);
145
    std::string getName();
146
    std::string getID();
147
};
148
149
class RADIO_SWITCH: public RADIO_EQ
150
{
151
    RC_433MHz main433MHz;
152
    STATE m_state = STATE::UNDEFINE;
153
public:
154
    RADIO_SWITCH(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
155
    ~RADIO_SWITCH();
156
    void on();
157
    void off();
158
    void onFor15sec();
159
    void onSunrise();
160
    void onSunset();
161
    void onLockHome();
162
    void onUnlockHome();
163
    STATE getState();
164
    std::string getName();
165
    std::string getID();
166
    void setCode(RADIO_EQ_CONFIG cfg);
167
    STATE m_sunrise = STATE::UNDEFINE;
168
    STATE m_sunset  = STATE::UNDEFINE;
169
};
170
171
class RADIO_EQ_CONTAINER
172
{
173
    std::map <std::string, RADIO_EQ* > m_radioEqMap;
174
    thread_data * my_data;
175
    nlohmann::json m_configJson;
176
public:
177
    RADIO_EQ_CONTAINER(thread_data * my_data);
178
    virtual ~RADIO_EQ_CONTAINER();
179
    void addRadioEq(RADIO_EQ_CONFIG cfg, RADIO_EQ_TYPE type);    
180
    void addRadioEq(RADIO_EQ_CONFIG cfg, const std::string& type);
181
    void deleteRadioEq(const std::string &name);
182
    virtual RADIO_EQ* getEqPointer(std::string name);
183
    std::vector<RADIO_SWITCH*> getSwitchPointerVector();
184
    std::vector<RADIO_BUTTON*> getButtonPointerVector();
185
    std::vector<RADIO_WEATHER_STATION *> getWeather_StationPtrVector();
186
    std::string listAllName();
187
    bool nameExist(const std::string &name);
188
    void loadConfig(const std::string &filePath);
189
    void saveConfig(const std::string &filePath);
190
};
191
192
class RADIO_EQ_CONTAINER_STUB : public RADIO_EQ_CONTAINER
193
{
194
    thread_data * k;
195
public:
196
    RADIO_EQ_CONTAINER_STUB(thread_data * k):RADIO_EQ_CONTAINER(k){this->k = k;}
197
198
    virtual ~RADIO_EQ_CONTAINER_STUB(){puts("~RADIO_EQ_CONTAINER_STUB()");}
199
    MOCK_METHOD1(getEqPointer, RADIO_EQ*(std::string name));
200
};
201
202
#endif // RADIO_SWITCH_H
/home/cyniu/GIT/malina/iDom_server_OOP/src/RADIO_433_eq/test/radio_433_test.cpp
1
#include <gtest/gtest.h>
2
#include <gmock/gmock.h>
3
#include "../radio_433_eq.h"
4
#include "../../iDomTools/test/iDomTools_fixture.h"
5
6
RC_433MHz::RC_433MHz(thread_data *test_my_data)
272
7
{
272
8
    this->m_my_data = test_my_data;
272
9
}
10
void RC_433MHz::sendCode(const std::string& code)
6
11
{
6
12
    std::cout << "sendCode(): " << code << std::endl;
6
13
}
14
std::string RC_433MHz::receiveCode()
0
15
{
0
16
    return "test";
0
17
}
18
class Switch_Class_fixture : public iDomTOOLS_ClassTest
19
{
20
21
};
22
TEST_F(Switch_Class_fixture, getSwitchPointerVector)
1
23
{
1
24
    auto v = test_rec.getSwitchPointerVector();
1
25
    EXPECT_EQ(v.size(),5);
1
26
}
27
28
TEST_F(Switch_Class_fixture, getButtonPointerVector)
1
29
{
1
30
    auto v = test_rec.getButtonPointerVector();
1
31
    EXPECT_EQ(v.size(),1);
1
32
}
33
34
TEST_F(Switch_Class_fixture, switch_alarm_on)
1
35
{
1
36
    RADIO_SWITCH* ptr = dynamic_cast<RADIO_SWITCH*>(test_rec.getEqPointer("ALARM"));
1
37
1
38
    EXPECT_EQ(ptr->getType(),RADIO_EQ_TYPE::SWITCH);
1
39
    puts("radio switch type");
1
40
    EXPECT_EQ(ptr->getState(),STATE::UNDEFINE);
1
41
    puts("radio switch state");
1
42
    ptr->on();
1
43
    EXPECT_EQ(ptr->getState(),STATE::ON);
1
44
    ptr->off();
1
45
    EXPECT_EQ(ptr->getState(),STATE::OFF);
1
46
    ptr->onSunset();
1
47
    EXPECT_EQ(ptr->getState(),STATE::OFF);
1
48
}
49
50
TEST_F(Switch_Class_fixture, weatherStruct)
1
51
{
1
52
    WEATHER_STRUCT test_WS;
3
53
    EXPECT_DOUBLE_EQ(0.0, test_WS.getTemperature())<<"Tempertura zla";
1
54
1
55
    test_WS.putData("20;03;LaCrosse;ID=0506;TEMP=0137;");
3
56
    EXPECT_DOUBLE_EQ(31.1, test_WS.getTemperature())<<"Tempertura zla";
1
57
1
58
    test_WS.putData("20;03;LaCrosse;ID=0506;TEMP=8130;");
3
59
    EXPECT_DOUBLE_EQ(-30.4, test_WS.getTemperature())<<"Tempertura zla";
1
60
}
61
62
TEST_F(Switch_Class_fixture, read_write_config_json)
1
63
{
1
64
    auto v = test_rec.getSwitchPointerVector();
1
65
    EXPECT_EQ(v.size(),5);
1
66
    test_rec.saveConfig(test_server_set.radio433MHzConfigFile);
1
67
    v = test_rec.getSwitchPointerVector();
1
68
    EXPECT_EQ(v.size(),5);
1
69
}
70
TEST_F(Switch_Class_fixture, addUnexistsRadioEq)
1
71
{
1
72
    RADIO_EQ_CONFIG tCfg;
1
73
    tCfg.name = "cyniu";
1
74
    tCfg.ID = "8899";
1
75
    std::string _name = tCfg.name;
1
76
    EXPECT_FALSE(test_rec.nameExist(_name));
1
77
    test_rec.addRadioEq(tCfg, "PIR");
1
78
    EXPECT_FALSE(test_rec.nameExist(_name));
1
79
}
80
81
TEST_F(Switch_Class_fixture, add_and_erase_switch)
1
82
{
1
83
    RADIO_EQ_CONFIG tCfg;
1
84
    tCfg.name = "test";
1
85
    test_rec.addRadioEq(tCfg, RADIO_EQ_TYPE::SWITCH);
1
86
    auto v = test_rec.getSwitchPointerVector();
1
87
    EXPECT_EQ(v.size(),6);
1
88
    test_rec.saveConfig(test_server_set.radio433MHzConfigFile);
1
89
    v = test_rec.getSwitchPointerVector();
1
90
    EXPECT_EQ(v.size(),6);
1
91
1
92
    ///////delete
1
93
    test_rec.deleteRadioEq(tCfg.name);
1
94
    v = test_rec.getSwitchPointerVector();
1
95
    EXPECT_EQ(v.size(),5);
1
96
    test_rec.saveConfig(test_server_set.radio433MHzConfigFile);
1
97
    v = test_rec.getSwitchPointerVector();
1
98
    EXPECT_EQ(v.size(),5);
1
99
}
100
101
TEST_F(Switch_Class_fixture, loadConfig)
1
102
{
1
103
    RADIO_EQ_CONTAINER test_rec(&test_my_data);
1
104
    test_rec.loadConfig("/mnt/ramdisk/433_eq_conf_fake.json");
1
105
1
106
    EXPECT_FALSE(test_rec.nameExist("firstt"));
1
107
    EXPECT_TRUE(test_rec.nameExist("locker"));
1
108
}
109
110
TEST_F(Switch_Class_fixture, getUnexistPtr)
1
111
{
1
112
    EXPECT_THROW(test_rec.getEqPointer("kokos"),std::string);
1
113
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/THERMOMETER_CONTAINER/test/thermometer_container_BT.cpp
1
#include <gtest/gtest.h>
2
#include <gmock/gmock.h>
3
#include "../../iDomTools/test/iDomTools_fixture.h"
4
#include "../thermometer_container.h"
5
6
class Thermometer_container_fixture :  public ::testing::Test //public iDomTOOLS_ClassTest
7
{
8
public:
9
    THERMOMETER_CONTAINER testThermo;
10
    std::string termoName = "test_thermometer";
11
    std::vector<std::string> v;
12
13
    void SetUp() final
4
14
    {
4
15
        std::vector<std::string> v = {"10.2","11.22"};
4
16
        testThermo.add("inside");
4
17
        testThermo.add("outside");
4
18
        testThermo.updateAll(&v);
4
19
        v = {"20.2","21.22"};
4
20
        testThermo.updateAll(&v);
4
21
        std::cout << "temepratura inside" << testThermo.getTemp("inside") << std::endl;
4
22
        std::cout << "temepratura outside" << testThermo.getTemp("outside") << std::endl;
4
23
        testThermo.updateStats("inside");
4
24
        testThermo.updateStats("outside");
4
25
        std::cout << "rozmiar mapy termoetrow: " << testThermo.sizeOf() << std::endl;
4
26
        testThermo.showAll();
4
27
        puts("SetUp() Thermometer_container_fixture");
4
28
        puts("--------------------------------------");
4
29
    }
30
};
31
TEST_F(Thermometer_container_fixture, returnUnexistPTR)
1
32
{
1
33
    EXPECT_THROW(testThermo.returnThermometerPtr("fake"),std::string);
1
34
}
35
36
TEST_F(Thermometer_container_fixture, getStatsByName)
1
37
{
1
38
    std::string returnedStr = testThermo.getStatsByName("inside");
1
39
    std::cout << "zwrocono " << returnedStr << std::endl;
1
40
    EXPECT_THAT(returnedStr, testing::HasSubstr("min: 20.2"));
1
41
    EXPECT_THAT(returnedStr, testing::HasSubstr("max: 20.2"));
1
42
}
43
44
TEST_F(Thermometer_container_fixture, getLast2)
1
45
{
1
46
    std::cout << "rozmiar mapy termoetrow: " << testThermo.sizeOf() << std::endl;
1
47
    testThermo.updateStats("inside");
1
48
    testThermo.updateStats("outside");
1
49
    testThermo.showAll();
1
50
    v = {"44.4","45.45"};
1
51
    testThermo.updateAll(&v);
1
52
    testThermo.updateStats("inside");
1
53
    testThermo.updateStats("outside");
1
54
    std::string returnedStr = testThermo.getStatsByName("inside");
1
55
    std::cout << "zwrocono " << returnedStr <<"||"<< std::endl;
1
56
    auto v = testThermo.getLast2("inside");
1
57
    EXPECT_EQ(v.first, 20.2);
1
58
    EXPECT_EQ(v.second, 44.4);
1
59
}
60
61
TEST_F(Thermometer_container_fixture, isMoreDiff)
1
62
{
1
63
    std::cout << "rozmiar mapy termoetrow: " << testThermo.sizeOf() << std::endl;
1
64
    testThermo.updateStats("inside");
1
65
    testThermo.updateStats("outside");
1
66
    testThermo.showAll();
1
67
    v = {"24.4","45.45"};
1
68
    testThermo.updateAll(&v);
1
69
    testThermo.updateStats("inside");
1
70
    testThermo.updateStats("outside");
1
71
    EXPECT_FALSE(testThermo.isMoreDiff("inside",15.5));
1
72
    EXPECT_TRUE(testThermo.isMoreDiff("outside",15.5));
1
73
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/THERMOMETER_CONTAINER/thermometer_container.cpp
1
#include "thermometer_container.h"
2
3
THERMOMETER *THERMOMETER_CONTAINER::returnThermometerPtr(const std::string& name)
216
4
{
216
5
    auto m = thermoMap.find(name);
216
6
    if (m != thermoMap.end())
215
7
        return &(m->second);
216
8
    else
1
9
    {
1
10
      throw std::string("thermometer not found!");
1
11
    }
216
12
}
13
14
THERMOMETER_CONTAINER::THERMOMETER_CONTAINER()
110
15
{
110
16
}
17
18
THERMOMETER::THERMOMETER(int iter):m_stats(iter)
220
19
{
220
20
}
21
22
void THERMOMETER_CONTAINER::add(const std::string &name)
220
23
{
220
24
    auto pair = std::make_pair(name, THERMOMETER(15));
220
25
    thermoMap.insert(pair);
220
26
}
27
28
void THERMOMETER_CONTAINER::setTemp(const std::string &name, double value)
34
29
{
34
30
    returnThermometerPtr(name)->m_thermometer.oldTemp = returnThermometerPtr(name)->m_thermometer.newTemp;
34
31
    returnThermometerPtr(name)->m_thermometer.newTemp = value;
34
32
}
33
34
double THERMOMETER_CONTAINER::getTemp(const std::string &name)
22
35
{
22
36
    return returnThermometerPtr(name)->m_thermometer.newTemp;
22
37
}
38
39
double THERMOMETER_CONTAINER::getOldTemp(const std::string &name)
14
40
{
14
41
    return returnThermometerPtr(name)->m_thermometer.oldTemp;
14
42
}
43
44
TEMPERATURE_STATE THERMOMETER_CONTAINER::getLastState(const std::string &name)
26
45
{
26
46
    return returnThermometerPtr(name)->m_thermometer.lastState;
26
47
}
48
49
void THERMOMETER_CONTAINER::setState(const std::string &name, TEMPERATURE_STATE state)
14
50
{
14
51
    returnThermometerPtr(name)->m_thermometer.lastState = state;
14
52
}
53
54
void THERMOMETER_CONTAINER::updateAll(std::vector<std::string> *vectorThermo)
17
55
{
17
56
    std::string in  = vectorThermo->at(0);
17
57
    std::string out = vectorThermo->at(1);
17
58
    setTemp("inside", std::stod(in));
17
59
    setTemp("outside",std::stod(out));
17
60
}
61
62
void THERMOMETER_CONTAINER::updateStats(const std::string &name)
16
63
{
16
64
    returnThermometerPtr(name)->m_stats.push_back(returnThermometerPtr(name)->m_thermometer.newTemp);
16
65
}
66
67
std::string THERMOMETER_CONTAINER::getStatsByName(const std::string &name)
2
68
{
2
69
    return returnThermometerPtr(name)->m_stats.stats();
2
70
}
71
72
bool THERMOMETER_CONTAINER::isMoreDiff(const std::string &name, double diff)
2
73
{
2
74
    return returnThermometerPtr(name)->m_stats.isMoreDiff(diff);
2
75
}
76
77
std::pair<double, double> THERMOMETER_CONTAINER::getLast2(const std::string &name)
1
78
{
1
79
    return returnThermometerPtr(name)->m_stats.getLast2();
1
80
}
81
82
int THERMOMETER_CONTAINER::sizeOf()
6
83
{
6
84
    return static_cast<int>(thermoMap.size());
6
85
}
86
87
void THERMOMETER_CONTAINER::showAll()
6
88
{
6
89
    for(auto n : thermoMap)
12
90
    {
12
91
        std::cout << n.first << " ";
12
92
    }
6
93
    std::cout << std::endl << "koniec prointowania w  " << std::endl;
6
94
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/blockQueue/blockqueue.cpp
1
#include "blockqueue.h"
2
#include "../iDom_server_OOP.h"
3
4
blockQueue::blockQueue()
45
5
{
45
6
}
7
std::mutex blockQueue::mutex_queue_char;
8
std::queue <MPD_COMMAND> blockQueue::_MPD_CommandQ;
9
void blockQueue::_add(MPD_COMMAND X)
35
10
{
35
11
    std::lock_guard <std::mutex>  lock (mutex_queue_char);
35
12
    if(_MPD_CommandQ.size() < 10)
34
13
    {
34
14
        _MPD_CommandQ.push(X);
34
15
    }
35
16
    else
1
17
    {
1
18
#ifdef BT_TEST
1
19
        std::string e = "za duzo w kolejce";
1
20
        throw e;
1
21
#else
22
        log_file_mutex.mutex_lock();
23
        log_file_cout << DEBUG << "za dużo danych w kolejce- nie dodaje "<< std::endl;
24
        log_file_mutex.mutex_unlock();
25
#endif
1
26
    }
35
27
}
28
29
MPD_COMMAND blockQueue::_get( )
14
30
{
14
31
    MPD_COMMAND temp = MPD_COMMAND::NULL_;
14
32
    std::lock_guard <std::mutex>  lock (mutex_queue_char);
14
33
    if (_MPD_CommandQ.empty() == false){
12
34
        temp = _MPD_CommandQ.front();
12
35
        _MPD_CommandQ.pop();
12
36
    }
14
37
    return temp;
14
38
}
39
40
int blockQueue::_size()
27.9M
41
{
27.9M
42
    std::lock_guard <std::mutex>  lock (mutex_queue_char);
27.9M
43
    return static_cast<int>(_MPD_CommandQ.size());
27.9M
44
}
45
46
void blockQueue::_clearAll()
21
47
{
21
48
     std::lock_guard <std::mutex>  lock (mutex_queue_char);
43
49
     while (_MPD_CommandQ.empty() == false){
22
50
         _MPD_CommandQ.pop();
22
51
     }
21
52
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/blockQueue/test/blockqueue_BT.cpp
1
#include <gtest/gtest.h>
2
#include "../blockqueue.h"
3
#include <thread>
4
#include <iostream>
5
6
class blockQueue_Class_fixture : public ::testing::Test
7
{
8
public:
4
9
    blockQueue_Class_fixture()  {  }
10
11
protected:
12
    blockQueue test_q;
13
14
    void SetUp() final
4
15
    {
4
16
        std::cout << "blockQueue_Class_fixture SetUp" << std::endl;
4
17
    }
18
19
    void TearDown() final
4
20
    {
4
21
        std::cout << "blockQueue_Class_fixture TearDown" << std::endl;
4
22
    }
23
    static void getFromQ_thread()
1
24
    {
1
25
        blockQueue q;
143k
26
        while(q._size() == 0 )
143k
27
        {
143k
28
        }
1
29
        EXPECT_EQ(q._get(), MPD_COMMAND::STOP);
27.7M
30
        while(q._size() == 0 )
27.7M
31
        {
27.7M
32
        }
1
33
        EXPECT_EQ(q._get(), MPD_COMMAND::STOP);
1
34
    }
35
36
    static void putToQ_thread(MPD_COMMAND c)
1
37
    {
1
38
        blockQueue q;
1
39
        q._add(c);
1
40
        sleep(1);
1
41
        q._add(c);
1
42
    }
43
};
44
45
TEST_F(blockQueue_Class_fixture, main)
1
46
{
1
47
    EXPECT_EQ(test_q._size(), 0);
1
48
    EXPECT_EQ(test_q._get(), MPD_COMMAND::NULL_);
1
49
    test_q._add(MPD_COMMAND::PLAY);
1
50
    EXPECT_EQ(test_q._size(), 1);
1
51
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
1
52
    EXPECT_EQ(test_q._size(), 0);
1
53
}
54
55
TEST_F(blockQueue_Class_fixture, inThread)
1
56
{
1
57
    std::thread get(blockQueue_Class_fixture::getFromQ_thread);
1
58
    std::thread put(blockQueue_Class_fixture::putToQ_thread,MPD_COMMAND::STOP);
1
59
    get.join();
1
60
    put.join();
1
61
}
62
63
TEST_F(blockQueue_Class_fixture, allClear)
1
64
{
1
65
    EXPECT_EQ(test_q._size(), 0);
1
66
    EXPECT_EQ(test_q._get(), MPD_COMMAND::NULL_);
1
67
    test_q._add(MPD_COMMAND::PLAY);
1
68
    EXPECT_EQ(test_q._size(), 1);
1
69
    test_q._add(MPD_COMMAND::PLAY);
1
70
    EXPECT_EQ(test_q._size(), 2);
1
71
    test_q._clearAll();
1
72
    EXPECT_EQ(test_q._size(), 0);
1
73
}
74
75
TEST_F(blockQueue_Class_fixture, capacityExceeded)
1
76
{
1
77
    test_q._clearAll();
1
78
    EXPECT_EQ(test_q._size(), 0);
1
79
11
80
    for (auto i = 0 ; i <10 ; ++i)
10
81
    {
10
82
      test_q._add(MPD_COMMAND::PLAY);
10
83
    }
1
84
1
85
    EXPECT_THROW(test_q._add(MPD_COMMAND::PLAY), std::string );
1
86
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/c_connection/c_connection.cpp
1
#include <iostream>
2
#include "c_connection.h"
3
4
C_connection::C_connection (thread_data  *my_data):c_socket(my_data->s_client_sock),
5
    c_from(my_data->from),recv_size(0)
1
6
{
1
7
    this -> pointer = &my_data->pointer;
1
8
    this -> my_data = my_data;
1
9
    this->m_encrypted = my_data->server_settings->encrypted;
1
10
    std::fill(std::begin(c_buffer),std::end(c_buffer),',');
1
11
    onStartConnection();
1
12
}
13
14
C_connection::~C_connection()
1
15
{
1
16
    if( mainCommandHandler != std::nullptr_t())
0
17
    {
0
18
        my_data->mainLCD->set_print_song_state(0);
0
19
        my_data->mainLCD->set_lcd_STATE(2);
0
20
        delete mainCommandHandler;
0
21
    }
1
22
    my_data->mainLCD->set_print_song_state(0);
1
23
    my_data->mainLCD->set_lcd_STATE(2);
1
24
#ifndef BT_TEST
25
    sleep(3);
26
#endif
1
27
    shutdown(c_socket, SHUT_RDWR );
1
28
    useful_F::clearThreadArray(my_data);
1
29
    puts("C_connection::~C_connection()");
1
30
}
31
32
33
int C_connection::c_send(int para)
0
34
{
0
35
    crypto(str_buf,m_encriptionKey,m_encrypted); //BUG  - naprawic czytanie flagi  z parametru klasy
0
36
    std::string  len = std::to_string( str_buf.size());
0
37
    crypto(len,m_encriptionKey,m_encrypted);
0
38
    if(( send( c_socket, len.c_str() ,len.length(), para ) ) <= 0 )
0
39
    {
0
40
        return -1;
0
41
    }
0
42
    recv_size = recv( c_socket, c_buffer , MAX_buf, para );
0
43
0
44
    if(recv_size < 0 )
0
45
    {
0
46
#ifndef BT_TEST
47
        log_file_mutex.mutex_lock();
48
        log_file_cout << ERROR << "C_connection::c_send(int para) recv() error - " << strerror(  errno ) <<   std::endl;
49
        log_file_mutex.mutex_unlock();
50
#endif
0
51
        return -1;
0
52
    }
0
53
    else if (recv_size == 0)
0
54
    {
0
55
        return -1;
0
56
    }
0
57
0
58
    auto len_send = str_buf.length();
0
59
0
60
    while (len_send > 0)
0
61
    {
0
62
        auto len_temp = send( c_socket, str_buf.c_str() ,str_buf.length(), para ) ;
0
63
        if(len_temp  <= 0 )
0
64
        {
0
65
            return -1;
0
66
        }
0
67
        len_send -= len_temp;
0
68
        str_buf.erase(0,len_temp);
0
69
    }
0
70
    return 0;
0
71
}
72
73
int C_connection::c_send(const std::string &command )
0
74
{
0
75
    str_buf = command;
0
76
    return c_send(0);
0
77
}
78
79
int C_connection::c_recv(int para)
0
80
{
0
81
    struct timeval tv;
0
82
    tv.tv_sec = 90;
0
83
    tv.tv_usec = 0;
0
84
    setsockopt(c_socket,SOL_SOCKET,SO_RCVTIMEO,(char*)&tv , sizeof(struct timeval));
0
85
0
86
    recv_size = recv(c_socket, c_buffer, MAX_buf, para);
0
87
0
88
    if(recv_size < 0)
0
89
    {
0
90
#ifndef BT_TEST
91
        log_file_mutex.mutex_lock();
92
        log_file_cout << ERROR << "C_connection::c_recv(int para) recv() error - " << strerror(  errno ) <<   std::endl;
93
        log_file_mutex.mutex_unlock();
94
#endif
0
95
        return -1;
0
96
    }
0
97
    else if (recv_size == 0)
0
98
    {
0
99
        return -1;
0
100
    }
0
101
    return recv_size;
0
102
}
103
104
int C_connection::c_analyse(int recvSize)
0
105
{
0
106
    std::string buf;
0
107
0
108
    buf = c_read_buf(recvSize);
0
109
    my_data->myEventHandler.run("command")->addEvent(buf);
0
110
    std::vector <std::string> command;
0
111
    useful_F::tokenizer(command," \n,", buf);
0
112
    str_buf = "unknown command\n";
0
113
0
114
    for(std::string  t : command)
0
115
    {
0
116
        str_buf += t+" ";
0
117
    }
0
118
0
119
    str_buf = mainCommandHandler->run(command,my_data);
0
120
0
121
    return true;
0
122
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/c_connection/c_connection2.cpp
1
#include "c_connection.h"
2
#include <iostream>
3
4
std::string C_connection::c_read_buf ( int  recvSize)
0
5
{
0
6
    std::string str_buf;
0
7
    for (int i = 0 ; i < recvSize; ++i)
0
8
    {
0
9
        str_buf.push_back( c_buffer[i]);
0
10
    }
0
11
    crypto(str_buf,m_encriptionKey,m_encrypted);
0
12
    return str_buf;
0
13
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/c_connection/c_connection_node.cpp
1
2
#include "c_connection.h"
3
#include <iostream>
4
5
////////  not used now
6
//void C_connection::c_start_master ()
7
//{
8
//    std::cout <<  " w pamieci jest " <<my_data->server_settings->AAS.size() <<" nodow\n";
9
//    for (unsigned int i =0 ; i<my_data->server_settings->AAS.size() ; ++i )
10
//    {
11
//        std::cout << "  jest ustawien id " <<  my_data->server_settings->AAS[i].id << std::endl;
12
//        std::cout << "  jest ustawien ip " <<  my_data->server_settings->AAS[i].SERVER_IP << std::endl;
13
//    }
14
//        while (1)
15
//        {
16
//             //c_recv_master_to();
17
//             c_recv_send_master();
18
//             std::cout << " odebralem w masterze \n";
19
//             //c_send_master_to(c_bufor_tmp[16]);
20
//        }
21
//}
22
23
24
//void C_connection::c_recv_send_master()
25
//{
26
//    while (1)
27
//    {
28
//        std::this_thread::sleep_for( std::chrono::milliseconds(50) );
29
30
//        mutex_who.lock();
31
//        if (  pointer->ptr_who[0] == my_data->server_settings->ID_server)
32
//        {
33
//            mutex_buf.lock();
34
35
//            for (int i =0 ; i < MAX_MSG_LEN ; ++i )
36
//            {
37
//                 pointer->ptr_buf[i]-=1;
38
//            }
39
//            pointer->ptr_who[0] =  pointer->ptr_who[1] ;
40
//            pointer->ptr_who[1] =  my_data->server_settings->ID_server;
41
//            mutex_buf.unlock();
42
//        }
43
//         mutex_who.unlock();
44
//    } // end while
45
//}
46
47
void C_connection::setEncriptionKey(const std::string& key)
0
48
{
0
49
    m_encriptionKey = key;
0
50
}
51
52
void C_connection::setEncrypted(bool flag)
0
53
{
0
54
    m_encrypted = flag;
0
55
}
56
57
void C_connection::crypto(std::string &toEncrypt, std::string key, bool encrypted)
2
58
{
2
59
    if (!encrypted){
0
60
          return;
0
61
      }
2
62
    unsigned int keySize = key.size()-1;
2
63
#ifdef BT_TEST
2
64
    std::cout << "key: " << key << " size: " << key.size() << std::endl;
2
65
#endif
42
66
    for (unsigned int i = 0; i < toEncrypt.size (); i++)
40
67
    {
40
68
        if (keySize == 0)   keySize = key.size()-1;
36
69
        else     --keySize;
40
70
        toEncrypt[i] ^=  key[keySize];
40
71
    }
2
72
}
73
74
void C_connection::onStartConnection()
1
75
{
1
76
//    log_file_mutex.mutex_lock();
1
77
//    log_file_cout << INFO<< "konstruuje nowy obiekt do komunikacj na gniezdzie " << c_socket <<  std::endl;
1
78
//    log_file_mutex.mutex_unlock();
1
79
}
80
81
void C_connection::onStopConnection()
0
82
{
0
83
    my_data->main_iDomTools->cameraLedOFF(my_data->server_settings->cameraLedOFF);
0
84
}
85
86
void C_connection::cryptoLog(std::string &toEncrypt)
0
87
{
0
88
    crypto(toEncrypt,m_encriptionKey,m_encrypted);
0
89
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/c_connection/test/c_connection_BT.cpp
1
#include <gtest/gtest.h>
2
#include "../../iDomTools/test/iDomTools_fixture.h"
3
4
#include "../c_connection.h"
5
6
class c_connection_fixture : public iDomTOOLS_ClassTest
7
{
8
public:
1
9
    c_connection_fixture() {
1
10
        this->test_connection = std::nullptr_t();
1
11
    }
12
13
protected:
14
    C_connection* test_connection;
15
    void SetUp() final
1
16
    {
1
17
        std::cout << "c_connection_fixture SetUp()" << std::endl;
1
18
        iDomTOOLS_ClassTest::SetUp();
1
19
        test_connection = new C_connection(&test_my_data);
1
20
    }
21
    void TearDown() final
1
22
    {
1
23
        delete test_connection;
1
24
        iDomTOOLS_ClassTest::TearDown();
1
25
        std::cout << "c_connection_fixture TearDown()" << std::endl;
1
26
    }
27
    void crypto_fixture(std::string &toEncrypt, std::string key)
2
28
    {
2
29
        test_connection->crypto(toEncrypt, std::move(key), true);
2
30
    }
31
};
32
33
TEST_F(c_connection_fixture, crypto)
1
34
{
1
35
    std::string key = "210116556";
1
36
    std::string test_msg = "kokosowa ksiezniczka";
1
37
    std::string toEncrypt = test_msg;
1
38
    crypto_fixture(toEncrypt, key);
1
39
21
40
    for(int i = 0; i < toEncrypt.size(); ++i)
20
41
    {
60
42
        EXPECT_NE(test_msg[i],toEncrypt[i]) << " niestety równe: " << toEncrypt[i]
60
43
                                            << " na indeksie: " << i;
20
44
    }
1
45
    std::cout << "wiadomość: " << test_msg << " zakodowane: "<< toEncrypt << std::endl;
1
46
    crypto_fixture(toEncrypt, key);
1
47
    std::cout << "wiadomość: " << test_msg << " odkodowane: "<< toEncrypt << std::endl;
3
48
    EXPECT_STREQ(toEncrypt.c_str(), test_msg.c_str()) << "wiadomosci nie są równe";
1
49
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/command/command.cpp
1
#include "command.h"
2
3
command::command(const std::string &commandName ) : commandName(commandName)
15
4
{
15
5
   // std::cout << "konstruktor command"<<std::endl;
15
6
}
7
8
command::~command()
15
9
{
15
10
  // puts("command::~command()");
15
11
}
12
13
std::string command::getCommandName()
0
14
{
0
15
    return commandName;
0
16
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/command/commandClass/../../433MHz/RFLink/rflinkhandler.h
1
#ifndef RFLINKHANDLER_H
2
#define RFLINKHANDLER_H
3
4
#include <map>
5
#include <exception>
6
#include "../../SerialPi/serialpi.h"
7
#include "../../iDom_server_OOP.h"
8
9
class WRONG_FORMAT : public std::exception{
10
11
};
12
13
struct RFLink_DEV{
14
    int m_counter = 0;
15
    std::string msg;
9
16
    void counter(){
9
17
        ++m_counter;
9
18
    }
19
2
20
    std::string read(){
2
21
        return std::to_string(m_counter) + " \t"+ msg;
2
22
    }
23
};
24
25
class RFLinkHandler
26
{
27
    thread_data *my_data;
28
    SerialPi serial_RFLink;
29
30
public:
31
32
    static std::mutex sm_RFLink_MUTEX;
33
    static std::string sm_RFLink_BUFOR;
34
35
    ////// temporarnie //////
36
    std::map<std::string, RFLink_DEV> rflinkMAP;
37
    /////////////////////////////
38
    RFLinkHandler(thread_data *my_data);
39
40
    bool init();
41
    //    void run();
42
    void flush();
43
    void sendCommand(std::string cmd);
44
    std::string sendCommandAndWaitForReceive(std::string cmd);
45
    std::string readFromRS232();
46
private:
47
    std::string internalReadFromRS232();
48
//#ifdef BT_TEST
49
public:
50
//#endif
51
    static std::string getArgumentValueFromRFLinkMSG(const std::string &msg, const std::string &var);
52
};
53
54
#endif // RFLINKHANDLER_H
/home/cyniu/GIT/malina/iDom_server_OOP/src/command/commandClass/../../RADIO_433_eq/radio_433_eq.h
1
#ifndef RADIO_SWITCH_H
2
#define RADIO_SWITCH_H
3
#include <gtest/gtest.h>
4
#include <gmock/gmock.h>
5
#include <map>
6
#include "../iDomStatus/idomstatus.h"
7
#include "../433MHz/RFLink/rflinkhandler.h"
8
9
#include "../433MHz/rc_433mhz.h"
10
#include "json.hpp"
11
12
struct WEATHER_STRUCT{
13
private:
14
    unsigned long int m_counter = 0;
15
protected:
16
    unsigned int m_humidity = 0;
17
    double m_temperature = 0.0;
18
    unsigned int m_barometricPressure = 0;
19
public:
2
20
    unsigned int getHumidity(){ return m_humidity; }
21
    double getTemperature(){ return m_temperature; }
0
22
    unsigned int getBarometricPressure(){ return m_barometricPressure; }
0
23
    std::string getDataString(){
0
24
        return "data: "+std::to_string(m_counter)+"\n"+"Humidity=" + std::to_string(getHumidity()) +"%\n"+
0
25
                "temperature= " + to_string_with_precision(getTemperature()) + "c\n"+
0
26
                "Pressure= " + std::to_string(getBarometricPressure())+ "kPa\n";
0
27
    }
28
29
    void putData(std::string data){
30
        std::string tempStr;
31
        int t = 0;
32
        ++m_counter;
33
        try{
34
            m_humidity = std::stoi( RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "HUM") );
35
        }
36
        catch (...){  }
37
        try{
38
            tempStr =  RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "TEMP");
39
            std::stringstream ss;
40
            ss << std::hex << tempStr.substr(tempStr.size()-3,tempStr.size());
41
            ss >> t;
42
            m_temperature = t / 10.0;
43
            if(tempStr.at(0) == '8'){
44
                m_temperature *= -1.0;
45
            }
46
        }
47
        catch (...){  }
48
        //std::cout << "DUPA:  "<<data<<" temp=" << m_temperature<< " hum="<<m_humidity<< std::endl;
49
    }
50
};
51
52
enum class RADIO_EQ_TYPE{
53
    SWITCH = 1,
54
    PIR,
55
    GATE,
56
    BUTTON,
57
    WEATHER_S,
58
    NONE
59
};
60
struct RADIO_EQ_CONFIG{
61
    std::string name = "NULL";
62
    std::string ID   = "NULL";
63
    std::string type = "NULL";
64
    std::string onCode  = "NULL";
65
    std::string offCode = "NULL";
66
    std::string on15sec = "NULL";
67
    std::string sunrise = "NULL";
68
    std::string sunset  = "NULL";
69
    std::string lock   = "NULL";
70
    std::string unlock = "NULL";
71
    void set(std::string name,
72
             std::string ID,
73
             std::string type,
74
             std::string onCode,
75
             std::string offCode,
76
             std::string on15sec,
77
             std::string sunrise,
78
             std::string sunset,
79
             std::string lock,
4
80
             std::string unlock){
4
81
        this->name = name;
4
82
        this->ID   = ID;
4
83
        this->type = type;
4
84
        this->onCode  = onCode;
4
85
        this->offCode = offCode;
4
86
        this->on15sec = on15sec;
4
87
        this->sunrise = sunrise;
4
88
        this->sunset  = sunset;
4
89
        this->lock   = lock;
4
90
        this->unlock = unlock;
4
91
    }
92
93
    nlohmann::json getJson(){
94
        nlohmann::json jj;
95
        jj["name"]  = name;
96
        jj["id"]    = ID;
97
        jj["type"]  = type;
98
        jj["ON"]    = onCode;
99
        jj["OFF"]   = offCode;
100
        jj["on15sec"] = on15sec;
101
        jj["sunrise"] = sunrise;
102
        jj["sunset"]  = sunset;
103
        jj["lock"]   = lock;
104
        jj["unlock"] = unlock;
105
        return jj;
106
    }
107
};
108
109
class RADIO_EQ{
110
public:
111
    RADIO_EQ();
112
    virtual ~RADIO_EQ();
113
    virtual STATE getState() = 0;
114
    virtual std::string getName() = 0;
115
    virtual std::string getID() = 0;
116
    virtual RADIO_EQ_TYPE getType();
117
protected:
118
    thread_data *m_my_data;
119
    RADIO_EQ_TYPE m_type;
120
public:
121
    RADIO_EQ_CONFIG m_config;
122
};
123
class RADIO_WEATHER_STATION: public RADIO_EQ
124
{
125
    STATE m_state = STATE::UNDEFINE;
126
127
public:
128
    RADIO_WEATHER_STATION(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
129
    ~RADIO_WEATHER_STATION();
130
    STATE getState();
131
    std::string getName();
132
    std::string getID();
133
    // data
134
    WEATHER_STRUCT data;
135
};
136
class RADIO_BUTTON: public RADIO_EQ
137
{
138
    STATE m_state = STATE::UNDEFINE;
139
140
public:
141
    RADIO_BUTTON(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
142
    ~RADIO_BUTTON();
143
    STATE getState();
144
    void setState(STATE s);
145
    std::string getName();
146
    std::string getID();
147
};
148
149
class RADIO_SWITCH: public RADIO_EQ
150
{
151
    RC_433MHz main433MHz;
152
    STATE m_state = STATE::UNDEFINE;
153
public:
154
    RADIO_SWITCH(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
155
    ~RADIO_SWITCH();
156
    void on();
157
    void off();
158
    void onFor15sec();
159
    void onSunrise();
160
    void onSunset();
161
    void onLockHome();
162
    void onUnlockHome();
163
    STATE getState();
164
    std::string getName();
165
    std::string getID();
166
    void setCode(RADIO_EQ_CONFIG cfg);
167
    STATE m_sunrise = STATE::UNDEFINE;
168
    STATE m_sunset  = STATE::UNDEFINE;
169
};
170
171
class RADIO_EQ_CONTAINER
172
{
173
    std::map <std::string, RADIO_EQ* > m_radioEqMap;
174
    thread_data * my_data;
175
    nlohmann::json m_configJson;
176
public:
177
    RADIO_EQ_CONTAINER(thread_data * my_data);
178
    virtual ~RADIO_EQ_CONTAINER();
179
    void addRadioEq(RADIO_EQ_CONFIG cfg, RADIO_EQ_TYPE type);    
180
    void addRadioEq(RADIO_EQ_CONFIG cfg, const std::string& type);
181
    void deleteRadioEq(const std::string &name);
182
    virtual RADIO_EQ* getEqPointer(std::string name);
183
    std::vector<RADIO_SWITCH*> getSwitchPointerVector();
184
    std::vector<RADIO_BUTTON*> getButtonPointerVector();
185
    std::vector<RADIO_WEATHER_STATION *> getWeather_StationPtrVector();
186
    std::string listAllName();
187
    bool nameExist(const std::string &name);
188
    void loadConfig(const std::string &filePath);
189
    void saveConfig(const std::string &filePath);
190
};
191
192
class RADIO_EQ_CONTAINER_STUB : public RADIO_EQ_CONTAINER
193
{
194
    thread_data * k;
195
public:
196
    RADIO_EQ_CONTAINER_STUB(thread_data * k):RADIO_EQ_CONTAINER(k){this->k = k;}
197
198
    virtual ~RADIO_EQ_CONTAINER_STUB(){puts("~RADIO_EQ_CONTAINER_STUB()");}
199
    MOCK_METHOD1(getEqPointer, RADIO_EQ*(std::string name));
200
};
201
202
#endif // RADIO_SWITCH_H
/home/cyniu/GIT/malina/iDom_server_OOP/src/command/commandClass/TEST/command_433mhz_BT.cpp
1
#include "../command_433mhz.h"
2
#include "../../../functions/functions.h"
3
#include "../../../RADIO_433_eq/radio_433_eq.h"
4
#include "../../../433MHz/RFLink/rflinkhandler.h"
5
#include "../../../iDomTools/test/iDomTools_fixture.h"
6
7
class command433MHz_Class_fixture : public iDomTOOLS_ClassTest
8
{
9
public:
10
    command433MHz_Class_fixture()
9
11
    {
9
12
        this->test_command_433MHz = std::nullptr_t();
9
13
        this->test_RFLink = std::nullptr_t();
9
14
    }
15
16
protected:
17
    std::vector<std::string> test_v= {"433MHz"};
18
    RFLinkHandler* test_RFLink;
19
    blockQueue test_q;
20
    command_433MHz* test_command_433MHz;
21
22
    void SetUp() final
9
23
    {
9
24
        iDomTOOLS_ClassTest::SetUp();
9
25
9
26
        test_q._clearAll();
9
27
9
28
        test_RFLink = new RFLinkHandler(&test_my_data);
9
29
        test_command_433MHz = new command_433MHz("433MHz");
9
30
        test_my_data.main_RFLink = test_RFLink;
9
31
        std::cout << "command433MHz_Class_fixture SetUp" << std::endl;
9
32
    }
33
34
    void TearDown() final
9
35
    {
9
36
        iDomTOOLS_ClassTest::TearDown();
9
37
        delete test_RFLink;
9
38
        delete test_command_433MHz;
9
39
        std::cout << "command433MHz_Class_fixture TearDown" << std::endl;
9
40
    }
41
};
42
43
TEST_F(command433MHz_Class_fixture, deleteSwitch)
1
44
{
1
45
    test_v.push_back("show");
1
46
    test_v.push_back("all");
1
47
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
48
    auto v = test_rec.getSwitchPointerVector();
1
49
    EXPECT_EQ(v.size(),5);
1
50
    test_v.clear();
1
51
    test_v.push_back("433MHz");
1
52
    test_v.push_back("delete");
1
53
    test_v.push_back("A");
1
54
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
55
    v = test_rec.getSwitchPointerVector();
1
56
    EXPECT_EQ(v.size(),4);
1
57
    test_v.clear();
1
58
    test_v.push_back("433MHz");
1
59
    test_v.push_back("show");
1
60
    test_v.push_back("all");
1
61
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
62
1
63
}
64
TEST_F(command433MHz_Class_fixture, deleteFakeSwitch)
1
65
{
1
66
    int actualSize = test_rec.getSwitchPointerVector().size();
1
67
    test_v.push_back("show");
1
68
    test_v.push_back("all");
1
69
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
70
    auto v = test_rec.getSwitchPointerVector();
1
71
    EXPECT_EQ(v.size(),actualSize);
1
72
    test_v.clear();
1
73
    test_v.push_back("433MHz");
1
74
    test_v.push_back("delete");
1
75
    test_v.push_back("fake");
1
76
    std::string  result = test_command_433MHz->execute(test_v,&test_my_data);
1
77
    EXPECT_THAT(result, testing::HasSubstr("not exist"));
1
78
    v = test_rec.getSwitchPointerVector();
1
79
    EXPECT_EQ(v.size(),actualSize);
1
80
    test_v.clear();
1
81
    test_v.push_back("433MHz");
1
82
    test_v.push_back("show");
1
83
    test_v.push_back("all");
1
84
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
85
}
86
87
TEST_F(command433MHz_Class_fixture, addSwitch)
1
88
{
1
89
    int actualSize = test_rec.getSwitchPointerVector().size();
1
90
    test_v.push_back("show");
1
91
    test_v.push_back("all");
1
92
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
93
    auto v = test_rec.getSwitchPointerVector();
1
94
    EXPECT_EQ(v.size(),actualSize);
1
95
    test_v.clear();
1
96
    test_v.push_back("433MHz");
1
97
    test_v.push_back("add");
1
98
    test_v.push_back("Aaa");
1
99
    test_v.push_back("1234");
1
100
    test_v.push_back("SWITCH");
1
101
    test_v.push_back("onCode_A");
1
102
    test_v.push_back("ofCode_A");
1
103
    test_v.push_back("on15sec_A");
1
104
    test_v.push_back("sunrise_A");
1
105
    test_v.push_back("sunset_A");
1
106
    test_v.push_back("lock_A");
1
107
    test_v.push_back("unlock_A");
1
108
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
109
    v = test_rec.getSwitchPointerVector();
1
110
    EXPECT_EQ(v.size(),actualSize+1);
1
111
    test_v.clear();
1
112
    test_v.push_back("433MHz");
1
113
    test_v.push_back("show");
1
114
    test_v.push_back("all");
1
115
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
116
}
117
118
TEST_F(command433MHz_Class_fixture, addExistingWeather)
1
119
{
1
120
    test_v.push_back("show");
1
121
    test_v.push_back("all");
1
122
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
123
    auto v = test_rec.getWeather_StationPtrVector();
1
124
    EXPECT_EQ(v.size(),1);
1
125
    test_v.clear();
1
126
    test_v.push_back("433MHz");
1
127
    test_v.push_back("add");
1
128
    test_v.push_back("first");
1
129
    test_v.push_back("1234");
1
130
    test_v.push_back("WEATHER");
1
131
    test_v.push_back("onCode_A");
1
132
    test_v.push_back("ofCode_A");
1
133
    test_v.push_back("on15sec_A");
1
134
    test_v.push_back("sunrise_A");
1
135
    test_v.push_back("sunset_A");
1
136
    test_v.push_back("lock_A");
1
137
    test_v.push_back("unlock_A");
1
138
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
139
    v = test_rec.getWeather_StationPtrVector();
1
140
    EXPECT_EQ(v.size(),1);
1
141
    test_v.clear();
1
142
    test_v.push_back("433MHz");
1
143
    test_v.push_back("show");
1
144
    test_v.push_back("all");
1
145
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
146
}
147
148
TEST_F(command433MHz_Class_fixture, missingParamiter_addSwitch)
1
149
{
1
150
    test_v.push_back("show");
1
151
    test_v.push_back("all");
1
152
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
153
    auto v = test_rec.getSwitchPointerVector();
1
154
    EXPECT_EQ(v.size(),5);
1
155
    test_v.clear();
1
156
    test_v.push_back("433MHz");
1
157
    test_v.push_back("add");
1
158
    test_v.push_back("Abc");
1
159
    test_v.push_back("1234");
1
160
    test_v.push_back("SWITCH");
1
161
    test_v.push_back("onCode_A");
1
162
    test_v.push_back("ofCode_A");
1
163
    test_v.push_back("on15sec_A");
1
164
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
3
165
    EXPECT_STREQ(result.substr(0, 15).c_str(), "wrong paramiter")<< "nie ma bledu";
1
166
    v = test_rec.getSwitchPointerVector();
1
167
    EXPECT_EQ(v.size(),5);
1
168
    test_v.clear();
1
169
    test_v.push_back("433MHz");
1
170
    test_v.push_back("show");
1
171
    test_v.push_back("all");
1
172
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
173
}
174
\
175
TEST_F(command433MHz_Class_fixture, add_wrongType_addSwitch)
1
176
{
1
177
    test_v.push_back("show");
1
178
    test_v.push_back("all");
1
179
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
180
    auto v = test_rec.getSwitchPointerVector();
1
181
    EXPECT_EQ(v.size(),5);
1
182
    test_v.clear();
1
183
    test_v.push_back("433MHz");
1
184
    test_v.push_back("add");
1
185
    test_v.push_back("Abc");
1
186
    test_v.push_back("1234");
1
187
    test_v.push_back("FAKE"); //here is wrong type
1
188
    test_v.push_back("onCode_A");
1
189
    test_v.push_back("ofCode_A");
1
190
    test_v.push_back("on15sec_A");
1
191
    test_v.push_back("sunrise_A");
1
192
    test_v.push_back("sunset_A");
1
193
    test_v.push_back("lock_A");
1
194
    test_v.push_back("unlock_A");
1
195
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
1
196
    EXPECT_STREQ(result.substr(0, 10).c_str(), "wrong type");
1
197
    std::cout << "wynik testu: " << result << std::endl;
1
198
    v = test_rec.getSwitchPointerVector();
1
199
    EXPECT_EQ(v.size(),5);
1
200
    test_v.clear();
1
201
    test_v.push_back("433MHz");
1
202
    test_v.push_back("show");
1
203
    test_v.push_back("all");
1
204
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
205
}
206
207
TEST_F(command433MHz_Class_fixture, add_wrongID_addSwitch)
1
208
{
1
209
    test_v.push_back("show");
1
210
    test_v.push_back("all");
1
211
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
212
    auto v = test_rec.getSwitchPointerVector();
1
213
    EXPECT_EQ(v.size(),5);
1
214
    test_v.clear();
1
215
    test_v.push_back("433MHz");
1
216
    test_v.push_back("add");
1
217
    test_v.push_back("Abc");
1
218
    test_v.push_back("dummy"); //here is wrong ID
1
219
    test_v.push_back("SWITCH");
1
220
    test_v.push_back("onCode_A");
1
221
    test_v.push_back("ofCode_A");
1
222
    test_v.push_back("on15sec_A");
1
223
    test_v.push_back("sunrise_A");
1
224
    test_v.push_back("sunset_A");
1
225
    test_v.push_back("lock_A");
1
226
    test_v.push_back("unlock_A");
1
227
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
1
228
    std::cout << "wynik testu: " << result << std::endl;
1
229
    EXPECT_STREQ(result.substr(0, 8).c_str(), "wrong ID");
1
230
    v = test_rec.getSwitchPointerVector();
1
231
    EXPECT_EQ(v.size(),5);
1
232
    test_v.clear();
1
233
    test_v.push_back("433MHz");
1
234
    test_v.push_back("show");
1
235
    test_v.push_back("all");
1
236
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
237
}
238
239
TEST_F(command433MHz_Class_fixture, show_switch)
1
240
{
1
241
    test_v.push_back("show");
1
242
    test_v.push_back("all");
1
243
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
244
    auto v = test_rec.getSwitchPointerVector();
1
245
    EXPECT_EQ(v.size(),5);
1
246
    test_v.clear();
1
247
    test_v.push_back("433MHz");
1
248
    test_v.push_back("show");
1
249
    test_v.push_back("switch");
1
250
1
251
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
1
252
    std::cout << "wynik testu: " << result << std::endl;
1
253
    EXPECT_STREQ(result.substr(0, 8).c_str(), "UNDEFINE");
1
254
    v = test_rec.getSwitchPointerVector();
1
255
    EXPECT_EQ(v.size(),5);
1
256
    test_v.clear();
1
257
    test_v.push_back("433MHz");
1
258
    test_v.push_back("show");
1
259
    test_v.push_back("all");
1
260
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
261
}
262
263
TEST_F(command433MHz_Class_fixture, show_aether)
1
264
{
1
265
    test_my_data.main_RFLink->rflinkMAP["kk"].msg = "astro";
1
266
    test_my_data.main_RFLink->rflinkMAP["kk"].m_counter = 99;
1
267
    test_my_data.main_RFLink->rflinkMAP["jj"].msg = "lock";
1
268
    test_my_data.main_RFLink->rflinkMAP["jj"].m_counter = 155;
1
269
    test_v.push_back("show");
1
270
    test_v.push_back("all");
1
271
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
1
272
    auto v = test_rec.getSwitchPointerVector();
1
273
    EXPECT_EQ(v.size(),5);
1
274
    test_v.clear();
1
275
    test_v.push_back("433MHz");
1
276
    test_v.push_back("show");
1
277
    test_v.push_back("aether");
1
278
1
279
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
1
280
    std::cout << "wynik testu: " << result << std::endl;
1
281
    EXPECT_THAT(result, testing::HasSubstr("astro"));
1
282
    EXPECT_THAT(result, testing::HasSubstr("lock"));
1
283
    EXPECT_THAT(result, testing::HasSubstr("99"));
1
284
    EXPECT_THAT(result, testing::HasSubstr("155"));
1
285
    v = test_rec.getSwitchPointerVector();
1
286
    EXPECT_EQ(v.size(),5);
1
287
    test_v.clear();
1
288
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/command/commandClass/TEST/command_ardu_BT.cpp
1
#include <gtest/gtest.h>
2
#include "../command_ardu.h"
3
#include "../../../functions/functions.h"
4
#include "../../../RADIO_433_eq/radio_433_eq.h"
5
#include "../../../433MHz/RFLink/rflinkhandler.h"
6
#include "../../../iDomTools/test/iDomTools_fixture.h"
7
8
class commandArdu_Class_fixture : public iDomTOOLS_ClassTest
9
{
10
public:
6
11
    commandArdu_Class_fixture()  {
6
12
        this->test_RFLink = std::nullptr_t();
6
13
        this->test_ardu = std::nullptr_t();
6
14
    }
15
16
protected:
17
    std::vector<std::string> test_v= {"ardu"};
18
    RFLinkHandler* test_RFLink;
19
    blockQueue test_q;
20
    command_ardu* test_ardu;
21
    void SetUp() final
6
22
    {
6
23
        iDomTOOLS_ClassTest::SetUp();
6
24
6
25
        test_q._clearAll();
6
26
6
27
        test_RFLink = new RFLinkHandler(&test_my_data);
6
28
        test_ardu = new command_ardu("ardu", &test_my_data);
6
29
        test_my_data.main_RFLink = test_RFLink;
6
30
        test_v.push_back("433MHz");
6
31
        std::cout << "commandArdu_Class_fixture SetUp" << std::endl;
6
32
    }
33
34
    void TearDown() final
6
35
    {
6
36
        iDomTOOLS_ClassTest::TearDown();
6
37
        delete test_RFLink;
6
38
        delete test_ardu;
6
39
        std::cout << "commandArdu_Class_fixture TearDown" << std::endl;
6
40
    }
41
42
};
43
44
TEST_F(commandArdu_Class_fixture, wrongMSGformat)
1
45
{
1
46
    test_v.push_back("EV1527;ID=01e7be;SWITCH=01;CMD=ON;"); // wronh msg format missing 20;
1
47
    EXPECT_THROW(test_ardu->execute(test_v, &test_my_data), WRONG_FORMAT);
1
48
}
49
50
TEST_F(commandArdu_Class_fixture, UnlockHome)
1
51
{
1
52
    test_idomTOOLS->lockHome();
1
53
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
1
54
1
55
    test_v.push_back("20;EV1527;ID=01e7be;SWITCH=01;CMD=ON;");
1
56
    test_ardu->execute(test_v, &test_my_data);
1
57
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
1
58
1
59
    EXPECT_EQ(test_q._size(),1);
1
60
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
1
61
    EXPECT_EQ(test_q._size(),0);
1
62
}
63
64
TEST_F(commandArdu_Class_fixture, LockHome)
1
65
{
1
66
    test_idomTOOLS->unlockHome();
1
67
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
1
68
1
69
    test_v.push_back("20;EV1527;ID=01e7be;SWITCH=01;CMD=ON;");
3
70
    for(auto i : {1,2,3}){
3
71
        test_ardu->execute(test_v, &test_my_data);
3
72
    }
1
73
1
74
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
1
75
    EXPECT_EQ(test_q._size(),1);
1
76
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP);
1
77
    EXPECT_EQ(test_q._size(),0);
1
78
}
79
80
TEST_F(commandArdu_Class_fixture, playMusic)
1
81
{
1
82
    test_idomTOOLS->unlockHome();
1
83
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
1
84
    EXPECT_EQ(test_status.getObjectState("listwa"),STATE::UNKNOWN);
1
85
    test_status.addObject("music",STATE::STOP);
1
86
1
87
    test_v.push_back("20;EV1527;ID=01e7be;SWITCH=01;CMD=ON;");
1
88
1
89
    test_ardu->execute(test_v, &test_my_data);
1
90
1
91
    EXPECT_EQ(test_q._size(),1);
1
92
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
1
93
    EXPECT_EQ(test_q._size(),0);
1
94
    EXPECT_EQ(test_status.getObjectState("listwa"),STATE::ON);
1
95
}
96
97
TEST_F(commandArdu_Class_fixture, stopMusic)
1
98
{
1
99
    test_idomTOOLS->unlockHome();
1
100
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
1
101
    EXPECT_EQ(test_status.getObjectState("listwa"),STATE::UNKNOWN);
1
102
    test_status.addObject("music",STATE::PLAY);
1
103
1
104
    test_v.push_back("20;EV1527;ID=01e7be;SWITCH=01;CMD=ON;");
1
105
1
106
    test_ardu->execute(test_v, &test_my_data);
1
107
1
108
    EXPECT_EQ(test_q._size(),1);
1
109
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP);
1
110
    EXPECT_EQ(test_q._size(),0);
1
111
    EXPECT_EQ(test_status.getObjectState("listwa"),STATE::OFF);
1
112
}
113
114
TEST_F(commandArdu_Class_fixture, weatherStationTemp)
1
115
{
1
116
    test_v.push_back("20;2A;LaCrosse;ID=0704;TEMP=8043;");
1
117
    test_ardu->execute(test_v, &test_my_data);
1
118
    RADIO_WEATHER_STATION* st = static_cast<RADIO_WEATHER_STATION*>(test_my_data.main_REC->getEqPointer("first"));
1
119
    EXPECT_DOUBLE_EQ(-6.7, st->data.getTemperature() );
1
120
    EXPECT_DOUBLE_EQ(0, st->data.getHumidity() );
1
121
    test_v[2] = "20;35;LaCrosse;ID=0704;HUM=42;";
1
122
    test_ardu->execute(test_v, &test_my_data);
1
123
    EXPECT_DOUBLE_EQ(42, st->data.getHumidity() );
1
124
    test_v[2] = "20;2A;LaCrosse;ID=0704;TEMP=0000;";
1
125
    test_ardu->execute(test_v, &test_my_data);
1
126
    EXPECT_DOUBLE_EQ(0, st->data.getTemperature() );
1
127
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/command/commandClass/command_433mhz.cpp
1
#include "command_433mhz.h"
2
#include "../../RADIO_433_eq/radio_433_eq.h"
3
#include "../../433MHz/RFLink/rflinkhandler.h"
4
5
command_433MHz::command_433MHz(const std::string &name):command(name)
9
6
{
9
7
}
8
9
command_433MHz::~command_433MHz()
9
10
{
9
11
    // puts("command_433MHz::~command_433MHz()");
9
12
}
13
14
std::string command_433MHz::execute(std::vector<std::string> &v, thread_data *my_data)
26
15
{
26
16
    std::string str_buf = "wrong paramiter\n" + help();
26
17
    if (v.size() > 2){
26
18
        //////////////////////////// switch
26
19
        if (v[1] == "show" && v[2] == "all"){
17
20
            str_buf = my_data->main_REC->listAllName();
17
21
        }
9
22
        else if (v[1] == "delete" && v.size() == 3)
2
23
        {
2
24
            if (my_data->main_REC->nameExist(v[2]) == false)
1
25
            {
1
26
                return "equipment "+ v[2]+" not exist ";
1
27
            }
1
28
            my_data->main_REC->deleteRadioEq(v[2]);
1
29
            str_buf = v[2] + " deleted";
1
30
        }
7
31
        else if (v[1] == "add" && v.size() == 12)  //zmień tu
4
32
        {
4
33
            RADIO_EQ_CONFIG cfg;
4
34
            cfg.set(v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11]); // zmień tu
4
35
            if (my_data->main_REC->nameExist(v[2]) == true)
1
36
            {
1
37
                return "equipment "+ v[2]+" exist ";
1
38
            }
3
39
            try
3
40
            {
3
41
                my_data->main_REC->addRadioEq(cfg,v[4]);
3
42
            }
3
43
            catch(const WRONG_FORMAT& )
1
44
            {
1
45
                return "wrong type "+v[4];
1
46
            }
3
47
            catch(const std::invalid_argument& )
1
48
            {
1
49
                return "wrong ID "+v[3];
1
50
            }
3
51
1
52
            str_buf = v[2] + " added";
1
53
            my_data->main_REC->saveConfig(my_data->server_settings->radio433MHzConfigFile);
1
54
        }
3
55
        else if (v[1] == "show" && v[2] == "switch"){
1
56
            str_buf = "";
1
57
            for (auto m_switch : my_data->main_REC->getSwitchPointerVector())
5
58
            {
5
59
                str_buf.append(stateToString(m_switch->getState())    );
5
60
            }
1
61
        }
2
62
        else if (v[1] == "show" && v[2] == "aether"){
1
63
            str_buf.clear();
1
64
            for(auto itr = my_data->main_RFLink->rflinkMAP.begin();
3
65
                itr != my_data->main_RFLink->rflinkMAP.end();
2
66
                itr++)
2
67
            {
2
68
                str_buf += itr->second.read();
2
69
                str_buf += '\n';
2
70
            }
1
71
            str_buf += ".";
1
72
1
73
        }
1
74
        else if (v[1] == "send" ){
0
75
            str_buf = "sended!;";
0
76
            my_data->main_RFLink->sendCommand(v[2]);
0
77
0
78
        }
1
79
        else if (v[1] == "switch"){
0
80
            try{
0
81
                RADIO_SWITCH *m_switch = dynamic_cast<RADIO_SWITCH*>(my_data->main_REC->getEqPointer(v[2]));
0
82
0
83
                if (v[3] == "ON") {
0
84
                    m_switch->on();
0
85
                    str_buf = " done ";
0
86
                }
0
87
                else if (v[3] == "OFF"){
0
88
                    m_switch->off();
0
89
                    str_buf = " done ";
0
90
                }
0
91
                else if (v[3] == "15s"){
0
92
                    m_switch->onFor15sec();
0
93
                    str_buf = " done ";
0
94
                }
0
95
                else{
0
96
                    str_buf = "unknown paramiter: ";
0
97
                    str_buf.append(v[3]);
0
98
                }
0
99
            }
0
100
            catch (std::string& error){
0
101
                str_buf = error;
0
102
            }
0
103
            my_data->main_iDomTools->saveState_iDom();
0
104
        }
26
105
        /////////////////////////////////////////////
26
106
    }
22
107
    return str_buf;
26
108
}
109
110
std::string command_433MHz::help()
26
111
{
26
112
    std::stringstream help;
26
113
    help << ("433MHz delete <name> - dalete radio equipment") <<std::endl;
26
114
    help << ("433MHz add <name> <ID> <type> <onCode> <offCode> <on15sec> <sunrise> <sunset> <lock> <unlock> - add radio equipment") <<std::endl;
26
115
    help << ("433MHz switch <name> ON/OFF/15s - change switch state") <<std::endl;
26
116
    help << ("433MHz show all - list all equipment by name") <<std::endl;
26
117
    help << ("433MHz show aether   - show aether devices by ID") <<std::endl;
26
118
    help << ("433MHz send <msg>    - send command") <<std::endl;
26
119
    return help.str();
26
120
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/command/commandClass/command_ardu.cpp
1
#include "command_ardu.h"
2
3
command_ardu::command_ardu(const std::string &name):command(name)
0
4
{
0
5
    this->m_mainRadioButton = std::nullptr_t();
0
6
}
7
8
command_ardu::command_ardu(const std::string& name, thread_data *my_data):command(name)
9
  ,m_button433MHzVector(my_data->main_REC->getButtonPointerVector())
6
10
{
6
11
    //m_button433MHzVector = my_data->main_REC->getButtonPointerVector();
6
12
    m_mainRadioButton = static_cast<RADIO_BUTTON*>(my_data->main_REC->getEqPointer("locker"));
6
13
6
14
    m_weatherStVe = my_data->main_REC->getWeather_StationPtrVector();
6
15
    m_mainWeatherStation = static_cast<RADIO_WEATHER_STATION*>(my_data->main_REC->getEqPointer("first"));
6
16
}
17
18
std::string command_ardu::execute(std::vector<std::string> &v, thread_data *my_data)
10
19
{
10
20
    std::string str_buf = " only for internal usage!";
10
21
    if (v.size() > 1){
10
22
        if(v[1] == "show"){
0
23
            RADIO_WEATHER_STATION* st = static_cast<RADIO_WEATHER_STATION*>(my_data->main_REC->getEqPointer("first"));
0
24
            str_buf = st->data.getDataString();
0
25
        }
10
26
        if(v[1] == "433MHz"){
10
27
            my_data->myEventHandler.run("433MHz")->addEvent("RFLink: "+v[2]);
10
28
            try {
10
29
                my_data->main_RFLink->
10
30
                        rflinkMAP[my_data->main_RFLink->getArgumentValueFromRFLinkMSG(v[2],
10
31
                        "ID")].counter();
10
32
                my_data->main_RFLink->
10
33
                        rflinkMAP[my_data->main_RFLink->getArgumentValueFromRFLinkMSG(v[2],
10
34
                        "ID")].msg = v[2];
10
35
            }
0
36
            catch(const std::string& e){
0
37
                std::cout << "wyjatek w szukaniu: " << e <<std::endl;
0
38
                std::cout << "co jest: " << m_mainRadioButton->getID() <<
0
39
                             " powinno być 01e7be" <<std::endl;
0
40
            }
10
41
            //TODO  add command
9
42
            try {
9
43
                if (m_mainRadioButton->getID() == my_data->main_RFLink->getArgumentValueFromRFLinkMSG(v[2],"ID") )
6
44
                {
6
45
                    my_data->main_iDomTools->button433mhzLockerPressed(m_mainRadioButton);
6
46
                }
9
47
            }
0
48
            catch (const std::string& e){  }
9
49
            try {
9
50
                if (m_mainWeatherStation->getID() == my_data->main_RFLink->getArgumentValueFromRFLinkMSG(v[2],"ID") )
3
51
                {
3
52
                    m_mainWeatherStation->data.putData(v[2]);
3
53
                }
9
54
            }
0
55
            catch (std::string& e){  }
9
56
        }
10
57
    }
9
58
    return str_buf;
10
59
}
60
61
std::string command_ardu::help()
0
62
{
0
63
    return " only for internal usege\n";
0
64
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/command/test/commandhandler_stub.cpp
1
#include <iostream>
2
#include "../commandhandler.h"
3
4
std::string commandHandler::run(std::vector<std::string> &v, thread_data *my_data)
0
5
{
0
6
    std::cout << "commandHandler::run(std::vector<std::string> &v, thread_data *my_data) "<<std::endl;
0
7
    return "stub done";
0
8
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/functions/functions2.cpp
1
#include <iostream>
2
#include <fstream>
3
#include <regex>
4
#include <iterator>
5
#include <vector>
6
7
#include "functions.h"
8
9
9
std::vector<std::string> useful_F::split(const std::string& s, char separator ){
9
10
    std::vector<std::string> output;
9
11
    std::string::size_type prev_pos = 0, pos = 0;
9
12
25
13
    while((pos = s.find(separator, pos)) != std::string::npos)
16
14
    {
16
15
        std::string substring( s.substr(prev_pos, pos-prev_pos) );
16
16
        output.push_back(substring);
16
17
        prev_pos = ++pos;
16
18
    }
9
19
    try
9
20
    {
9
21
        output.push_back(s.substr(prev_pos, pos-prev_pos)); // Last word
9
22
    }
9
23
    catch (...)
0
24
    {
0
25
#ifndef BT_TEST
26
        log_file_mutex.mutex_lock();
27
        log_file_cout << CRITICAL << "wyjatek substr() w useful_F::split() !!!!!!"<< std::endl;
28
        log_file_mutex.mutex_unlock();
29
#endif
0
30
    }
9
31
    return output;
9
32
}
33
thread_data* useful_F::myStaticData = std::nullptr_t();
34
void useful_F::setStaticData(thread_data *my_dataPtr)
0
35
{
0
36
    myStaticData = my_dataPtr;
0
37
}
38
1
39
void useful_F::tokenizer ( std::vector <std::string> &command, std::string separator, std::string &text){
1
40
    std::string temp;
1
41
1
42
    for(char n: text)
13
43
    { // the initializer may be an array
13
44
        bool is_sep = false;
13
45
        for(char m: separator)
26
46
        {
26
47
            if (n == m)
2
48
            {
2
49
                is_sep = true;
2
50
            }
26
51
        }
13
52
        if (is_sep == false)
11
53
        {
11
54
            temp += n;
11
55
        }
13
56
        else
2
57
        {
2
58
            if (!temp.empty())
2
59
            {
2
60
                command.push_back( temp);
2
61
                temp = "";
2
62
            }
2
63
        }
13
64
    }
1
65
    if (!temp.empty())
1
66
    {
1
67
        command.push_back(temp);
1
68
    }
1
69
}
70
71
////// watek sleeper
72
void useful_F::sleeper_mpd (thread_data  *my_data)
1
73
{
1
74
    unsigned int t = 60/my_data->sleeper;
1
75
    unsigned int k = 0;
1
76
11
77
    for (; my_data->sleeper >0 ; my_data->sleeper-- )
10
78
    {
10
79
        useful_F::sleep_1min();
10
80
        k += t;
10
81
        my_data->main_iDomTools->ledClear(0,k);
10
82
    }
1
83
    my_data->main_iDomTools->ledOFF();
1
84
    my_data->main_iDomTools->MPD_stop();
1
85
    my_data->main_iDomTools->turnOff433MHzSwitch("listwa");
1
86
#ifndef BT_TEST
87
    log_file_mutex.mutex_lock();
88
    log_file_cout << INFO<< "zaczynam procedure konca watku SLEEP_MPD" <<  std::endl;
89
    log_file_mutex.mutex_unlock();
90
#endif
1
91
    try
1
92
    {
11
93
        for (int i =0 ; i< iDomConst::MAX_CONNECTION;++i)
10
94
        {
10
95
            if (my_data->main_THREAD_arr[i].thread_ID == std::this_thread::get_id())
0
96
            {
0
97
                //my_data->main_THREAD_arr[i].thread.detach();
0
98
                my_data->main_THREAD_arr[i].thread_name ="  -empty-  ";
0
99
                my_data->main_THREAD_arr[i].thread_ID =  std::thread::id();
0
100
                my_data->main_THREAD_arr[i].thread_socket = 0;
0
101
                break;
0
102
            }
10
103
        }
1
104
    }
1
105
    catch (std::system_error &e)
0
106
    {
0
107
#ifndef BT_TEST
108
        log_file_mutex.mutex_lock();
109
        log_file_cout << ERROR<< "zlapano wyjatek w  watku SLEEP_MPD: " << e.what()<< std::endl;
110
        log_file_mutex.mutex_unlock();
111
#endif
0
112
    }
1
113
#ifndef BT_TEST
114
    log_file_mutex.mutex_lock();
115
    log_file_cout << INFO<< "koniec  watku SLEEP_MPD" <<  std::endl;
116
    log_file_mutex.mutex_unlock();
117
#endif
1
118
}
119
120
std::string useful_F::RSHash(const std::string& data, unsigned int b, unsigned int a)
0
121
{
0
122
    time_t act_time;
0
123
    struct tm * act_date;
0
124
    time(&act_time);
0
125
    act_date = localtime(&act_time);
0
126
    char buffer[10];
0
127
    strftime(buffer,10,"%M%H%w",act_date);
0
128
    std::string str(buffer);
0
129
    str+=data;
0
130
    unsigned int hash = 0;
0
131
0
132
    for(std::size_t i = 0; i < str.length(); i++)
0
133
    {
0
134
        hash = hash * a + str[i];
0
135
        a    = a * b;
0
136
    }
0
137
    return std::to_string((hash & 0x7FFFFFFF));
0
138
}
139
/home/cyniu/GIT/malina/iDom_server_OOP/src/functions/tests/functions_BT.cpp
1
#include <gtest/gtest.h>
2
#include "../functions.h"
3
#include "../../RADIO_433_eq/radio_433_eq.h"
4
#include "../../iDomTools/test/iDomTools_fixture.h"
5
6
class functions_fixture : public iDomTOOLS_ClassTest{
7
8
};
9
10
void useful_F::sleep_1min()
10
11
{
10
12
    std::cout << "sleep_1min()"<<std::endl;
10
13
}
14
TEST(functions_, tokenizer)
1
15
{
1
16
     std::string test_msg = "one=two three";
1
17
     std::vector<std::string> test_v;
1
18
1
19
     EXPECT_EQ(test_v.size(), 0);
1
20
     useful_F::tokenizer(test_v,"= ",test_msg);
1
21
1
22
     EXPECT_EQ(test_v.size(),3);
1
23
     EXPECT_STREQ(test_v.at(2).c_str(),"three");
1
24
}
25
26
TEST(functions_, removeHtmlTag)
1
27
{
1
28
     std::string test_msg = "<html>test</html>";
1
29
     std::string test_pure_str = useful_F_libs::removeHtmlTag(test_msg);
1
30
1
31
     EXPECT_STREQ(test_pure_str.c_str(),"test");
1
32
}
33
34
TEST(functions_, repalceAll)
1
35
{
1
36
     std::string test_msg = "one two three";
1
37
     std::string test_pure_str = useful_F_libs::replaceAll(test_msg,"two","zero");
1
38
1
39
     EXPECT_STREQ(test_pure_str.c_str(),"one zero three");
1
40
}
41
42
TEST(functions_, split)
1
43
{
1
44
    std::string test_msg = "one two three";
1
45
    std::vector<std::string> test_v;
1
46
1
47
    EXPECT_EQ(test_v.size(), 0);
1
48
    test_v = useful_F::split(test_msg,' ');
1
49
1
50
    EXPECT_EQ(test_v.size(),3);
1
51
    EXPECT_STREQ(test_v.at(2).c_str(),"three");
1
52
}
53
54
TEST_F(functions_fixture, sleepThread)
1
55
{
1
56
    Thread_array_struc test_THRARRSTR;
1
57
    test_my_data.main_THREAD_arr = &test_THRARRSTR;
1
58
1
59
    MPD_info test_ptr_MPD;
1
60
    test_ptr_MPD.volume = 3;
1
61
    test_my_data.ptr_MPD_info = &test_ptr_MPD;
1
62
1
63
    RADIO_EQ_CONTAINER_STUB stub_rec(&test_my_data);
1
64
    test_my_data.main_REC = (&stub_rec);
1
65
    test_my_data.alarmTime.time = Clock::getTime();
1
66
    test_my_data.alarmTime.state = STATE::ACTIVE;
1
67
1
68
    RADIO_EQ_CONFIG cfg;
1
69
    cfg.name = "listwa";
1
70
    cfg.ID = "209888";
1
71
    cfg.onCode = "send ON";
1
72
    cfg.offCode= "send OFF";
1
73
    RADIO_EQ* test_RS = new RADIO_SWITCH(&test_my_data,cfg,RADIO_EQ_TYPE::SWITCH);
1
74
    EXPECT_CALL(stub_rec, getEqPointer("listwa")).WillRepeatedly(testing::Return(test_RS));
1
75
1
76
    test_my_data.sleeper = 10;
1
77
1
78
    blockQueue test_q;
1
79
    test_q._clearAll();
1
80
    EXPECT_EQ(test_q._size(),0);
1
81
    useful_F::sleeper_mpd(&test_my_data);
1
82
    EXPECT_EQ(test_q._size(),1);
3
83
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP)<<"NIE ZATRZYMANO MUZYKI :(";
1
84
    delete test_RS;
1
85
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/functions/tests/functions_stub.cpp
1
#include "../functions.h"
2
3
void useful_F::clearThreadArray(thread_data *my_data)
1
4
{
1
5
    std::cout << "useful_F::clearThreadArray(thread_data *my_data)"<<std::endl;
1
6
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomSaveState/idom_save_state.cpp
1
#include <iostream>     // std::cout
2
#include <fstream>
3
#include "idom_save_state.h"
4
#include "../iDom_server_OOP.h"
5
6
iDom_SAVE_STATE::iDom_SAVE_STATE(const std::string &path): m_path(path)
18
7
{
18
8
#ifdef BT_TEST
18
9
    puts("iDom_SAVE_STATE::iDom_SAVE_STATE()");
18
10
#endif
18
11
}
12
13
iDom_SAVE_STATE::~iDom_SAVE_STATE()
18
14
{
18
15
#ifdef BT_TEST
18
16
    puts("iDom_SAVE_STATE::~iDom_SAVE_STATE()");
18
17
#endif
18
18
}
19
20
nlohmann::json iDom_SAVE_STATE::read()
2
21
{
2
22
    std::lock_guard<std::mutex> lGuard(m_mutex);
2
23
    // read a JSON file
2
24
    std::ifstream i(m_path);
2
25
    nlohmann::json j;
2
26
    i >> j;
2
27
#ifndef BT_TEST
28
    log_file_mutex.mutex_lock();
29
    log_file_cout << INFO << "czytam zapisany stan parametrow iDom" << std::endl;
30
    log_file_mutex.mutex_unlock();
31
#endif
2
32
    return j;
2
33
}
34
35
void iDom_SAVE_STATE::write(const nlohmann::json &jj)
17
36
{
17
37
    std::lock_guard<std::mutex> lGuard(m_mutex);
17
38
    // write prettified JSON to another file
17
39
    std::ofstream o(m_path);
17
40
    o << std::setw(4) << jj << std::endl;
17
41
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomSaveState/test/iDomSaveState_BT.cpp
1
#include <gtest/gtest.h>
2
3
#include "test_data.h"
4
#include "../idom_save_state.h"
5
#include "json.hpp"
6
7
TEST(iDomSaveState, write_and_read)
1
8
{
1
9
    iDom_SAVE_STATE test_saveState("/mnt/ramdisk/iDomStateTest.save");
1
10
    nlohmann::json test_json ;
1
11
1
12
    test_json["happy"] = true;
1
13
    test_json["pi"] = 3.14;
1
14
1
15
    nlohmann::json test_json_in_json;
1
16
    test_json_in_json["name"] = "cyniu";
1
17
    test_json_in_json["age"] = 30;
1
18
1
19
    test_json["person"] = test_json_in_json;
1
20
1
21
    test_saveState.write(test_json);
1
22
    nlohmann::json test_json2 = test_saveState.read();
3
23
    EXPECT_DOUBLE_EQ(test_json.at("pi").get<double>(),
3
24
                     test_json2.at("pi").get<double>()) << "wartosci pi nie sa rowne";
1
25
3
26
    EXPECT_TRUE(test_json2.at("happy").get<bool>()) << " nie jest happy";
1
27
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomStatus/idomstatus.cpp
1
#include "idomstatus.h"
2
3
iDomSTATUS::iDomSTATUS()
56
4
{
56
5
}
6
7
void iDomSTATUS::addObject(std::string name, STATE st)
277
8
{
277
9
    std::lock_guard < std::mutex > lock ( m_lockGuard);
277
10
    m_stateMAP.insert(std::make_pair(name,st));
277
11
}
12
13
void iDomSTATUS::setObjectState(const std::string& name, STATE st)
39
14
{
39
15
    std::lock_guard < std::mutex > lock ( m_lockGuard);
39
16
    auto i = m_stateMAP.find(name);
39
17
    if (i != m_stateMAP.end()){
29
18
        i->second = st;
29
19
    }
39
20
    else
10
21
    {
10
22
        lock.~lock_guard();
10
23
        addObject(name,st);
10
24
    }
39
25
}
26
27
STATE iDomSTATUS::getObjectState(const std::string& name)
26
28
{
26
29
    std::lock_guard < std::mutex > lock ( m_lockGuard);
26
30
    auto i = m_stateMAP.find(name);
26
31
    if (i != m_stateMAP.end())
20
32
    {
20
33
        return i->second ;
20
34
    }
6
35
    return STATE::UNKNOWN;
26
36
}
37
38
std::string iDomSTATUS::getObjectStateString(const std::string& name)
50
39
{
50
40
    std::lock_guard < std::mutex > lock ( m_lockGuard);
50
41
    auto i = m_stateMAP.find(name);
50
42
    if (i != m_stateMAP.end())
38
43
    {
38
44
        return stateToString( i->second) ;
38
45
    }
12
46
    return stateToString(STATE::UNKNOWN) + " "+name;
50
47
}
48
49
std::string iDomSTATUS::getAllObjectsStateString()
1
50
{
1
51
    std::stringstream st;
1
52
    st << "state: ";
1
53
    std::lock_guard < std::mutex > lock( m_lockGuard);
1
54
    for (auto elm : m_stateMAP)
7
55
    {
7
56
        st << elm.first << "=";
7
57
        st << stateToString(elm.second) << " ";
7
58
    }
1
59
    return st.str();
1
60
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/../../libs/Statistic/statistic.h
1
#ifndef STATISTIC_H
2
#define STATISTIC_H
3
#include <iostream>
4
#include <deque>
5
#include <numeric>
6
#include <algorithm>
7
#include <sstream>
8
#include <cmath>
9
#include <vector>
10
11
template <class T>
12
class STATISTIC
13
{
14
public:
15
    STATISTIC(unsigned int size): m_size(size)
16
16
    {
16
17
16
18
    }
19
    void resize(unsigned int i){
20
        if (i < m_size){
21
            while(m_dequeue.size()> i){
22
                pop_front();
23
            }
24
        }
25
        m_size = i;
26
    }
27
    T size(){
28
        return  static_cast<T>(m_dequeue.size());
29
    }
30
    void push_front(T v){
31
        if (m_dequeue.size() >= m_size){
32
            pop_back();
33
        }
34
        m_dequeue.push_front(v);
35
    }
292
36
    void push_back(T v){
292
37
        if (m_dequeue.size() >= m_size){
0
38
            pop_front();
0
39
        }
292
40
        m_dequeue.push_back(v);
292
41
    }
42
    void pop_back(){
43
        m_dequeue.pop_back();
44
        // std::cout <<"pop_back"<<std::endl;
45
    }
0
46
    void pop_front(){
0
47
        m_dequeue.pop_front();
0
48
        // std::cout <<"pop_front"<<std::endl;
0
49
    }
50
    ///////////////////////////////////////////// statistic /////////////////////////////
8
51
    T median(){
8
52
        auto backup = m_dequeue;
8
53
        std::sort(backup.begin(), backup.end());
8
54
        if (backup.size() % 2 != 0){
2
55
            return backup[backup.size() / 2];
2
56
        }
6
57
        else{
6
58
            T m = backup[backup.size() / 2] + backup[(backup.size() / 2)-1];
6
59
            return m /2 ;
6
60
        }
8
61
    }
62
    T sum(){
63
        return std::accumulate(m_dequeue.begin(), m_dequeue.end(), static_cast<T>(0));
64
    }
65
66
    T average(){
67
        T av  = sum() /size();
68
        return av;
69
    }
70
71
    T max(){
72
        T max = m_dequeue[0];
73
        for (auto v : m_dequeue){
74
            if (v > max){
75
                max = v;
76
            }
77
        }
78
        return max;
79
    }
80
81
    T min(){
82
        T min = m_dequeue[0];
83
        for (auto v : m_dequeue){
84
            if (v < min){
85
                min = v;
86
            }
87
        }
88
        return min;
89
    }
90
91
    T range(){
92
        return max() - min();
93
    }
94
95
    T standardDeviation(){
96
        double standardDeviation = 0.0;
97
        T _av = average();
98
99
        for(int i = 0; i < size(); ++i){
100
            standardDeviation += pow(m_dequeue.at(i) - _av, 2);
101
        }
102
        return sqrt(standardDeviation / size());
103
    }
104
105
    T coefficientOfVariation(){
106
107
        return (standardDeviation()/average()) /** 100*/;
108
    }
109
8
110
    T mode(){
8
111
8
112
        T _mode = 0;
8
113
        T _modeTemp = 0;
8
114
        int counter = 1;
8
115
        int modeCounter = 1;
8
116
        auto backup = m_dequeue;
8
117
        if(m_dequeue.size() == 1)
2
118
        {
2
119
            return m_dequeue.at(0);
2
120
        }
6
121
        std::sort(backup.begin(), backup.end());
6
122
#ifdef BT_TEST
6
123
        std::cout << " " << std::endl;
6
124
        for (auto i : backup)
144
125
        {
144
126
            std::cout << i << " ";
144
127
        }
6
128
        std::cout << " " << std::endl;
6
129
#endif
6
130
        _mode = _modeTemp = backup.at(0);
6
131
        backup.pop_front();
6
132
        for (auto b : backup)
138
133
        {
138
134
            if (_modeTemp == b)
120
135
            {
120
136
                modeCounter++;
120
137
            }
138
138
            else
18
139
            {
18
140
                _modeTemp = b;
18
141
                modeCounter = 1;
18
142
            }
138
143
138
144
            if(counter < modeCounter)
72
145
            {
72
146
                counter = modeCounter;
72
147
                _mode = _modeTemp;
72
148
            }
138
149
        }
6
150
#ifdef BT_TEST
6
151
        std::cout << " moda: " << _mode << " wystepuje razy " << counter << std::endl;
6
152
#endif
6
153
        return _mode;
8
154
    }
155
156
    float trend(){
157
        int down = 0;
158
        int eq = 0;
159
        int up = 0;
160
        int lp = 0;
161
        T diff = 0;
162
        T first = m_dequeue[0];
163
164
        for (auto i = 1 ; i < m_dequeue.size(); ++i){
165
            if (first < m_dequeue[i]){
166
                up++;
167
                if (m_dequeue[i] - first > diff){
168
                    diff = m_dequeue[i] - first;
169
                    lp = i;
170
                }
171
            }
172
            if (first == m_dequeue[i]){ eq++;}
173
            if (first > m_dequeue[i]){
174
                if (diff < first - m_dequeue[i] ){
175
                    diff = first - m_dequeue[i];
176
                    lp = i;
177
                }
178
                down++;
179
            }
180
            first = m_dequeue[i];
181
        }
182
        std::cout <<"up "<<up<<" eq "<< eq << " down "<< down <<" max diff "<< diff<<" lp "<<lp << std::endl;
183
        return 2.2;
184
    }
185
186
    bool isMoreDiff(T diff){
187
        if (m_dequeue.size()>2){
188
            T d = m_dequeue.at( m_dequeue.size()-2)
189
                    - m_dequeue.at( m_dequeue.size() - 1);
190
            d = fabs(d);
191
            if (d > diff && m_alarm == false){
192
                m_alarm = true;
193
                return true;
194
            }
195
            if (d <= diff){
196
                m_alarm = false;
197
                return false;
198
            }
199
        }
200
        return false;
201
    }
202
    std::pair<double,double> getLast2(){
203
        if (m_dequeue.size()>2){
204
            return std::make_pair(static_cast<double>(m_dequeue.at( m_dequeue.size()-2)),
205
                                  static_cast<double>(m_dequeue.at( m_dequeue.size()-1))    );
206
        }
207
#ifdef BT_TEST
208
        puts("no data - return 0.0 0.0");
209
#endif
210
        return std::make_pair(0.0,0.0);
211
    }
212
213
    /////////////////////////////////////////////////////////////////////////////////////
214
    void print(){
215
        for(auto n : m_dequeue){
216
            std::cout << ","<< n ;
217
        }
218
        std::cout << " " <<std::endl;
219
    }
220
221
222
    std::string stats(){
223
224
        std::stringstream ss(" brak danych =(");
225
        if(size()>0)
226
        {
227
            ss.str("");
228
            ss <<"rozmiar tablicy: "<< size() <<std::endl
229
              << "min: "<< min() <<std::endl
230
              << "max: "<< max()<<std::endl
231
              << "srednia " << average() <<std::endl
232
              << "mediana " << median()  <<std::endl
233
              << "odchylenie st "<< standardDeviation() << std::endl
234
              << "wspolczynnik zmiennosci " << coefficientOfVariation() <<"%"<< std::endl
235
              << "Dominanta " << mode();
236
237
238
            ss << std::endl
239
               << "data " <<  std::endl;
240
            for(auto n : m_dequeue){
241
                ss << "|"<< n ;
242
            }
243
        }
244
        ss <<  std::endl;
245
        return ss.str();
246
    }
247
248
private:
249
    unsigned int m_size;
250
    std::deque <T> m_dequeue;
251
    bool m_alarm = false;
252
};
253
254
#endif // STATISTIC_H
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/../../libs/useful/useful.h
1
#ifndef Iusefull_H
2
#define Iusefull_H
3
4
#include <iostream>
5
#include <string>
6
#include <vector>
7
#include <ostream>
8
#include <chrono>
9
#include <sstream>
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <iomanip>
13
#ifndef ANDROID
14
#include "json.hpp"
15
#endif
16
17
std::vector<std::string> split_string(const std::string& s, char separator );
18
19
class useful_F_libs {
20
public:
21
    static  void write_to_mkfifo(const std::string &path, const std::string &msg);
22
    static  std::string read_from_mkfifo(const std::string &path);
23
    static size_t  WriteCallback(void *contents, size_t size, size_t nmemb, void *userp);
24
    static std::string find_tag (const std::string &temp);
25
    //////////////////// HTTP req //////////////////////////
26
    static std::string httpPost(const std::string &url, int timeoutSeconds);
27
    static std::string httpPost(const std::string &url);
28
    static void downloadFile(const std::string &url, const std::string &path, int timeoutSeconds);
29
    static std::string replaceAll(std::string str, const std::string& from, const std::string& to);
30
    static std::string removeHtmlTag(std::string &data);
31
    /////////////////////  JSON ////////////////////////////
32
33
#ifndef ANDROID
34
    static nlohmann::json getJson(const std::string &url);
35
#endif
36
};
37
namespace std
38
{
39
40
#ifdef ANDROID
41
template <typename T>
42
int stoi(T s){
43
    return atoi(s.c_str());
44
}
45
#endif
46
47
template <typename T>
48
std::string to_string(T value)
49
{
50
    std::ostringstream os ;
51
    os << value ;
52
    return os.str() ;
53
}
54
} // namespace std
55
56
template <typename T>
57
std::string to_string_with_precision(const T a_value, const int n = 4)
16
58
{
16
59
    std::ostringstream out;
16
60
    out << std::setprecision(n) << a_value;
16
61
    return out.str();
16
62
}
63
64
struct Clock{
65
private:
66
    std::time_t m_time;
67
68
public:
69
    unsigned int m_h = 0;
70
    unsigned int m_min = 0;
71
    Clock () {}
72
    Clock(std::string t){
73
        std::vector<std::string> vt = split_string(t,':');
74
        int h = std::stoi(vt.at(0));
75
        int m = std::stoi(vt.at(1));
76
        set(static_cast <unsigned int>(h),static_cast <unsigned int>(m));
77
    }
78
79
    Clock(unsigned int h, unsigned int m) {
80
        set(h,m);
81
    }
82
    /////////////////////////////////////////////////////////////////////////////////////
83
    void set(unsigned int h, unsigned int m){
84
        if (h<24 && m <60){
85
            this->m_h = h;
86
            this->m_min = m;
87
        }
88
        else {
89
            throw 0;
90
        }
91
    }
92
    /////////////////////////////////////////////////////////////////////////////////////
93
    const std::string getString(){
94
        std::stringstream ret;
95
        if (m_h < 10) {
96
            ret << "0";
97
        }
98
        ret << m_h;
99
        ret << ":";
100
        if (m_min < 10) {
101
            ret << "0";
102
        }
103
        ret << m_min;
104
        return ret.str();
105
    }
106
    /////////////////////////////////////////////////////////////////////////////////////
107
    bool operator == (const Clock & c){
108
        if ((this->m_h == c.m_h) && (this->m_min == c.m_min)){
109
            return true;
110
        }
111
        else{
112
            return false;
113
        }
114
    }
115
    /////////////////////////////////////////////////////////////////////////////////////
116
    bool operator != (const Clock & c){
117
        if ((this->m_h != c.m_h) || (this->m_min != c.m_min)){
118
            return true;
119
        }
120
        else{
121
            return false;
122
        }
123
    }
124
    /////////////////////////////////////////////////////////////////////////////////////
125
    friend std::ostream & operator<< (std::ostream &w ,  Clock &c) {
126
        return w << c.getString();
127
    }
128
    /////////////////////////////////////////////////////////////////////////////////////
129
    bool operator < (const Clock& c){
130
        if (this->m_h < c.m_h){
131
            return true;
132
        }
133
        else{
134
            if (this->m_h == c.m_h && this->m_min < c.m_min){
135
                return true;
136
            }
137
        }
138
        return false;
139
    }
140
    /////////////////////////////////////////////////////////////////////////////////////
141
    bool operator > (const Clock& c){
142
        if (this->m_h > c.m_h){
143
            return true;
144
        }
145
        else{
146
            if (this->m_h == c.m_h && this->m_min > c.m_min){
147
                return true;
148
            }
149
        }
150
        return false;
151
    }
152
    /////////////////////////////////////////////////////////////////////////////////////
153
    bool operator >= (const Clock& c){
154
        if (this->m_h > c.m_h){
155
            return true;
156
        }
157
        else if (this->m_h == c.m_h){
158
159
            if (this->m_min >= c.m_min){
160
                return true;
161
            }
162
        }
163
        return false;
164
    }
165
    /////////////////////////////////////////////////////////////////////////////////////
166
    bool operator <= (const Clock& c){
167
        if (this->m_h < c.m_h){
168
            return true;
169
        }
170
        else if (this->m_h == c.m_h){
171
172
            if (this->m_min <= c.m_min){
173
                return true;
174
            }
175
        }
176
        return false;
177
    }
178
    /////////////////////////////////////////////////////////////////////////////////////
179
    Clock  operator + (const Clock& c){
180
        unsigned int minutes, hours;
181
        minutes = m_min+ c.m_min;
182
        hours = m_h + c.m_h;
183
        if (minutes >59){
184
            minutes =  minutes % 60 ;
185
            hours+=1;
186
        }
187
        if (hours >= 24){
188
            hours-=24;
189
        }
190
        return  Clock(hours, minutes);
191
192
    }
193
    /////////////////////////////////////////////////////////////////////////////////////
194
    Clock&  operator += (const Clock& c){
195
        unsigned int minutes, hours;
196
        minutes = m_min+ c.m_min;
197
        hours = m_h + c.m_h;
198
        if (minutes >59){
199
            minutes =  minutes % 60 ;
200
            hours+=1;
201
        }
202
        if (hours >= 24){
203
            hours-=24;
204
        }
205
        this->m_h = hours;
206
        this->m_min = minutes;
207
        return *this;
208
209
    }
210
    /////////////////////////////////////////////////////////////////////////////////////
211
212
    unsigned int toSeconds(){
213
        return toSeconds(Clock(this->m_h, this->m_min) );
214
    }
215
    /////////////////////////////////////////////////////////////////////////////////////
216
217
    static unsigned int toSeconds(Clock t){
218
        return ((t.m_h*60) + t.m_min)*60;
219
    }
220
    /////////////////////////////////////////////////////////////////////////////////////
221
222
    static Clock fromSeconds(unsigned int sec){
223
        unsigned int h = sec/3600;
224
        unsigned int min = sec%3600;
225
        min = min/60;
226
        return Clock(h,min);
227
    }
228
    /////////////////////////////////////////////////////////////////////////////////////
229
230
    static Clock periodOfTime(Clock start, Clock end)
231
    {
232
        if (end >= start){
233
            return Clock::fromSeconds(end.toSeconds() - start.toSeconds()  );
234
        }
235
        else{
236
            return Clock::fromSeconds(end.toSeconds() + ( Clock::toSeconds(Clock(23,59))+ 60 - start.toSeconds() ) );
237
        }
238
        //return diff;
239
    }
240
    /////////////////////////////////////////////////////////////////////////////////////
241
    static Clock getTime()
242
    {
243
        time_t now = time(0);
244
        tm *ltm = localtime(&now);
245
        return Clock( static_cast <unsigned int>(ltm->tm_hour),static_cast <unsigned int>(ltm->tm_min) );
246
    }
247
    /////////////////////////////////////////////////////////////////////////////////////
248
    void stopwatchStart()
249
    {
250
        m_time = std::time(nullptr);
251
    }
252
    /////////////////////////////////////////////////////////////////////////////////////
253
    unsigned int  stopwatchStopAndGetResult()
254
    {
255
        return static_cast<unsigned int>(std::time(nullptr) - m_time);
256
    }
257
};
258
259
enum class STATE {
260
    OFF,
261
    ON,
262
    UNKNOWN,
263
    PLAY,
264
    PAUSE,
265
    STOP,
266
    ACTIVE,
267
    DEACTIVE,
268
    WORKING,
269
    DEFINE,
270
    UNDEFINE,
271
    LOCK,
272
    UNLOCK,
273
    EMPTY,
274
    FULL,
275
    SEND_OK,
276
    SEND_NOK
277
    //WARNING remember add new state to stateToString() usefull.cpp
278
};
279
280
281
std::string stateToString(STATE s);
282
283
#endif
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/../RADIO_433_eq/../433MHz/RFLink/../../iDom_server_OOP.h
1
#ifndef GLOBAL_H
2
#define GLOBAL_H
3
4
#include <iostream>
5
#include <fstream>
6
#include <string>
7
#include <cstdlib>
8
#include <pthread.h>
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <sys/socket.h>
12
#include <sys/types.h>
13
#include <netinet/in.h>
14
#include <vector>
15
#include <thread>
16
#include <arpa/inet.h>
17
#include <netinet/in.h>
18
#include <unistd.h>
19
#include <sys/fcntl.h>
20
#include <unistd.h>
21
#include <errno.h>
22
#include <signal.h>
23
#include <time.h>
24
#include <wiringPi.h>
25
#include <chrono>
26
27
// MOJE BIBLIOTEKI
28
#include "KEY/key.h"
29
#include "logger/logger.hpp"
30
#include "files_tree/files_tree.h"
31
#include "menu_tree/menu_tree.h"
32
#include "LCD_c/lcd_c.h"
33
#include "command/command.h"
34
#include "../libs/event_counters/event_counters_handler.h"
35
#include "iDomTools/idomtools.h"
36
#include "iDomStatus/idomstatus.h"
37
#include "iDomSaveState/idom_save_state.h"
38
39
#define log_file_cout  f_log //std::cout   zmien f_log na std::cout  i bedzie wypisywac na ekran
40
#define log_file_mutex f_log
41
42
enum class iDomStateEnum{
43
    CLOSE = 0,
44
    RELOAD,
45
    ERROR,
46
    WORKING,
47
    HARD_RELOAD
48
};
49
50
namespace iDomConst
51
{
52
constexpr int MAX_CONNECTION = 10;
53
constexpr int FREE  = 1;
54
constexpr int RS232 = 11;
55
constexpr int CLOCK = 12;
56
constexpr int ok    =  0;
57
constexpr int GPIO_SPIK  = 21;
58
constexpr int GPIO_PRINTER = 22;
59
constexpr int BUTTON_PIN = 25;
60
}
61
struct ALERT
62
{
63
    Clock time;
64
    STATE state = STATE::DEACTIVE;
65
    unsigned int fromVolume =  48;
66
    unsigned int toVolume = 58;
67
    unsigned int radioID = 8;
68
};
69
70
extern std::string  _logfile  ;
71
extern Logger log_file_mutex;
72
extern std::string buffer;
73
74
enum class TEMPERATURE_STATE;
75
enum class PILOT_KEY;
76
77
struct MPD_info{
78
    std::string title   = "NULL";
79
    std::string radio   = "NULL";
80
    std::string artist  = "NULL";
81
    int volume  = 0;
82
    bool isPlay = false;
83
    int currentSongID = 0;
84
    std::vector <std::string> songList = {"NULL"};
85
};
86
struct s_pointer{
87
    unsigned int *ptr_who;
88
    int32_t *ptr_buf;
89
};
90
91
struct Thread_array_struc {
92
    std::thread thread;
93
    std::thread::id thread_ID = std::thread::id(0);
94
    std::string thread_name;
95
    int thread_socket = 0;
96
};
97
98
struct address_another_servers {
99
    int id;
100
    std::string SERVER_IP;
101
};
102
103
struct FTP_SERVER{
104
    std::string URL;
105
    std::string user;
106
    std::string pass;
107
};
108
struct iDOM_STATE{
109
    STATE houseState = STATE::UNDEFINE;
110
111
};
112
113
struct config{
114
    std::string portRS232;
115
    std::string portRS232_clock;
116
    std::string BaudRate;
117
    std::string RFLinkPort;
118
    std::string RFLinkBaudRate;
119
    int PORT;
120
    std::string SERVER_IP;
121
    std::string MPD_IP;
122
    std::string MOVIES_DB_PATH;
123
    std::string MENU_PATH;
124
    std::string THREAD_MPD   = "NULL";
125
    std::string THREAD_IRDA  = "NULL";
126
    std::string THREAD_CRON  = "NULL";
127
    std::string THREAD_RS232 = "NULL";
128
    std::string THREAD_DUMMY = "NULL";
129
    std::string TS_KEY= " gg ";
130
    std::string cameraLedON = "";
131
    std::string cameraLedOFF ="";
132
    std::string cameraURL="";
133
    std::string facebookAccessToken = "";
134
    std::string viberToken = "NULL";
135
    std::string viberAvatar;
136
    std::vector <std::string> viberReceiver;
137
    std::string viberSender;
138
    std::string radio433MHzConfigFile;
139
    std::string omxplayerFile = "NULL";
140
    int ID_server = 0;
141
    int v_delay  ;
142
    bool encrypted = true;
143
144
    FTP_SERVER ftpServer;
145
    std::string lightningApiURL = "NULL";
146
    std::string saveFilePath = "NULL";
147
};
148
149
struct LED_Strip{
150
    std::string from ;
151
    std::string to ;
152
    std::string R ;
153
    std::string G ;
154
    std::string B ;
155
    std::string colorName;
156
157
    LED_Strip (int from, int to, int r, int g, int b, std::string colorName = "NULL"):from(std::to_string(from)),
158
        to(std::to_string(to)),
159
        R(std::to_string(r)),
160
        G(std::to_string(g)),
161
        B(std::to_string(b)),
162
        colorName(colorName)
163
    {
164
165
    }
166
    LED_Strip (std::string from, std::string to, std::string r, std::string g, std::string b, std::string colorName = "NULL"):
167
        from(from),
168
        to(to),
169
        R(r),
170
        G(g),
171
        B(b),
172
        colorName(colorName)
173
    {
174
175
    }
176
177
    void set (std::string from, std::string to, std::string r, std::string g, std::string b, std::string colorName = "NULL"){
178
        this->from =from;
179
        this->to = to;
180
        R = r;
181
        G = g;
182
        B = b;
183
        this->colorName =colorName;
184
    }
185
186
    void set (int from, int to, int r, int g, int b, std::string colorName = "NULL"){
187
        this->from = std::to_string(from);
188
        this->to = std::to_string(to);
189
        R = std::to_string(r);
190
        G = std::to_string(g);
191
        B = std::to_string(b);
192
        this->colorName =colorName;
193
    }
194
195
    std::string getColorName() const{
196
        return colorName;
197
    }
198
13
199
    std::string get(unsigned int _from, unsigned int _to) const{
13
200
        if (_from != 0 || _to != 60){
9
201
            return "LED:["+std::to_string(_from)+"-"+std::to_string(_to)+"-"+R+"-"+G+"-"+B+"];";
9
202
        }
4
203
        return "LED:["+from+"-"+to+"-"+R+"-"+G+"-"+B+"];";
13
204
    }
205
206
    std::string makeCommand(std::string from, std::string to, std::string R, std::string G, std::string B){
207
        return "LED:["+from+"-"+to+"-"+R+"-"+G+"-"+B+"];";
208
    }
209
};
210
211
struct pilot_led{
212
    unsigned int counter=0;
213
    std::vector<LED_Strip> colorLED   = { LED_Strip(1,60,237,145,33 ,"carrot orange"),
214
                                          LED_Strip(1,60,255,0,0    ,"red"),
215
                                          LED_Strip(1,60,0,255,0    ,"green"),
216
                                          LED_Strip(1,60,0,0,255    ,"blue"),
217
                                          LED_Strip(1,60,255,255,255,"white"),
218
                                          LED_Strip(1,60,255,255,0  ,"yellow"),
219
                                          LED_Strip(1,60,0,255,255  ,"cyan"),
220
                                          LED_Strip(1,60,255,0,255  ,"magenta")
221
                                        };
222
};
223
224
class command ;  // for struc thread_data req
225
class iDomTOOLS;
226
class RADIO_EQ_CONTAINER;
227
class RFLinkHandler;
228
229
struct thread_data{
230
    int s_client_sock;
231
    struct sockaddr_in from;
232
    struct config *server_settings = NULL;
233
    struct s_pointer pointer;
234
    LCD_c *mainLCD = NULL;
235
    files_tree *main_tree = NULL;
236
    menu_tree *main_MENU = NULL;
237
    iDomTOOLS *main_iDomTools = NULL;
238
    RFLinkHandler *main_RFLink = NULL;
239
    Thread_array_struc *main_THREAD_arr = NULL;
240
    time_t start;
241
    time_t now_time;
242
    int sleeper;
243
    std::map <std::string, std::unique_ptr <KEY>  > key_map;
244
    MPD_info *ptr_MPD_info = NULL;
245
    pilot_led * ptr_pilot_led = NULL;
246
    std::map <std::string, std::unique_ptr<command> >* commandMapPtr = NULL;
247
    event_counters_handler myEventHandler;
248
    std::string encriptionKey = "40%";
249
    iDomSTATUS *main_iDomStatus;
250
    iDOM_STATE idom_all_state;
251
    ALERT alarmTime;
252
    RADIO_EQ_CONTAINER *main_REC;
253
    iDomStateEnum iDomProgramState = iDomStateEnum::WORKING;
254
255
};
256
257
struct thread_data_rs232{
258
    std::string portRS232;
259
    std::string portRS232_clock;
260
    std::string BaudRate;
261
    struct s_pointer pointer;
262
};
263
264
#endif // GLOBAL_H
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/idomtools.cpp
1
#include <algorithm>
2
#include <fstream>
3
#include <string>
4
#include <typeinfo>
5
6
#include "idomtools.h"
7
#include "../functions/functions.h"
8
#include "../../libs/emoji/emoji.h"
9
#include "../../libs/Statistic/statistic.h"
10
#include "../CRON/cron.hpp"
11
#include "../RADIO_433_eq/radio_433_eq.h"
12
#include "json.hpp"
13
14
iDomTOOLS::iDomTOOLS(thread_data *myData): key(myData->server_settings->TS_KEY)
53
15
{
53
16
    puts("iDomTOOLS::iDomTOOLS()");
53
17
    my_data = myData;
53
18
53
19
    //////////////////////////////////// temeprature /////////////////
53
20
53
21
    allThermometer.add("inside");
53
22
    allThermometer.add("outside");
53
23
    allThermometerUpdate.add("inside");
53
24
    allThermometerUpdate.add("outside");
53
25
    /////////////////////////////////////////////////////////////////
53
26
#ifndef BT_TEST
27
    pinMode(iDomConst::GPIO_SPIK, OUTPUT);    // gpio pin do zasilania glosnikow
28
    digitalWrite(iDomConst::GPIO_SPIK,LOW);
29
    pinMode(iDomConst::GPIO_PRINTER,OUTPUT);  /// gpio pin do zsilania drukarki
30
    digitalWrite(iDomConst::GPIO_PRINTER,LOW);
31
    pinMode(iDomConst::BUTTON_PIN, INPUT);   //  gpio pin przycisku
32
33
    if (wiringPiISR (iDomConst::BUTTON_PIN, INT_EDGE_BOTH, &useful_F::button_interrupt) < 0 ) {
34
35
        log_file_cout.mutex_lock();
36
        log_file_cout << CRITICAL <<"Unable to setup ISR RISING "<<std::endl;
37
        log_file_cout.mutex_unlock();
38
39
    }
40
#endif
53
41
    my_data->main_iDomStatus->addObject("cameraLED",STATE::UNKNOWN);
53
42
    my_data->main_iDomStatus->addObject("printer",STATE::OFF);
53
43
    my_data->main_iDomStatus->addObject("speakers",STATE::OFF);
53
44
    my_data->main_iDomStatus->addObject("alarm",STATE::DEACTIVE);
53
45
53
46
    ///////// setup viber api
53
47
    m_viber.setAvatar(my_data->server_settings->viberAvatar);
53
48
    m_viber.setAccessToken(my_data->server_settings->viberToken);
53
49
    m_viber.setURL("https://chatapi.viber.com/pa/send_message");
53
50
    ///////// setup faceboook api
53
51
    m_facebook.setAccessToken(my_data->server_settings->facebookAccessToken);
53
52
53
53
    //////// button 433MHz
53
54
    buttonPointerVector = my_data->main_REC->getButtonPointerVector();
53
55
53
56
    lastButton433MHzLockUnlockTime = Clock::getTime() + Clock(23,58);
53
57
53
58
}
59
60
TEMPERATURE_STATE iDomTOOLS::hasTemperatureChange(const std::string& thermometerName, double reference, double histereza )
14
61
{
14
62
    reference += 0.0055;
14
63
    const auto newTemp = allThermometer.getTemp(thermometerName);
14
64
    const auto oldTemp = allThermometer.getOldTemp(thermometerName);
14
65
    const auto lastState = allThermometer.getLastState(thermometerName);
14
66
    if (newTemp >= reference + histereza &&
8
67
            oldTemp  < reference + histereza &&
4
68
            lastState != TEMPERATURE_STATE::Over)
4
69
    {
4
70
        my_data->myEventHandler.run("test")->addEvent("over: new "+  to_string_with_precision(newTemp)+" old: "
4
71
                                                      +to_string_with_precision(oldTemp)+" ref: "
4
72
                                                      +to_string_with_precision(reference));
4
73
        allThermometer.setState(thermometerName, TEMPERATURE_STATE::Over);
4
74
        return TEMPERATURE_STATE::Over;
4
75
    }
10
76
    else if (newTemp <= reference - histereza &&
5
77
             oldTemp >  reference - histereza &&
2
78
             lastState != TEMPERATURE_STATE::Under)
2
79
    {
2
80
        my_data->myEventHandler.run("test")->addEvent("under: new "+to_string_with_precision(newTemp)+" old: "
2
81
                                                      +to_string_with_precision(oldTemp)+" ref: "
2
82
                                                      +to_string_with_precision(reference));
2
83
        allThermometer.setState(thermometerName, TEMPERATURE_STATE::Under);
2
84
        return TEMPERATURE_STATE::Under;
2
85
    }
10
86
    else
8
87
    {
8
88
        my_data->myEventHandler.run("test")->addEvent("noChanges: new "+to_string_with_precision(newTemp)+" old: "
8
89
                                                      +to_string_with_precision(oldTemp)+" ref: "+to_string_with_precision(reference));
8
90
8
91
        allThermometer.setState(thermometerName, TEMPERATURE_STATE::NoChanges);
8
92
        return TEMPERATURE_STATE::NoChanges;
8
93
    }
0
94
    my_data->myEventHandler.run("test")->addEvent("unknown: new "+to_string_with_precision(newTemp)+" old: "
0
95
                                                  +to_string_with_precision(oldTemp)+" ref: "+to_string_with_precision(reference));
0
96
0
97
    return TEMPERATURE_STATE::Unknown;
14
98
}
99
100
void iDomTOOLS::sendSMSifTempChanged(const std::string& thermomethernName, int reference)
14
101
{
14
102
    TEMPERATURE_STATE status = hasTemperatureChange(thermomethernName,reference,0.5);
14
103
    std::string m = "temperature "+thermomethernName+" over "+ EMOJI::emoji(E_emoji::NORTH_EAST_ARROW)
14
104
            + to_string_with_precision(reference);
14
105
14
106
    if (status == TEMPERATURE_STATE::Over){
4
107
        my_data->myEventHandler.run("temperature")->addEvent(m);
4
108
        if (reference < 2){
1
109
            sendViberMsg(m,my_data->server_settings->viberReceiver.at(0),my_data->server_settings->viberSender);
1
110
            sendViberMsg(m,my_data->server_settings->viberReceiver.at(1),my_data->server_settings->viberSender);
1
111
        }
3
112
        else{
3
113
            sendViberMsg(m,my_data->server_settings->viberReceiver.at(0),my_data->server_settings->viberSender);
3
114
        }
4
115
    }
10
116
    else if (status == TEMPERATURE_STATE::Under){
2
117
        m ="temperature " + thermomethernName+" under "+EMOJI::emoji(E_emoji::SOUTH_EAST_ARROW)
2
118
                +to_string_with_precision(reference);
2
119
        my_data->myEventHandler.run("temperature")->addEvent(m);
2
120
        if (reference < 2){
1
121
            sendViberPicture(m,"http://canacopegdl.com/images/cold/cold-14.jpg",
1
122
                             my_data->server_settings->viberReceiver.at(0),
1
123
                             my_data->server_settings->viberSender);
1
124
            sendViberPicture(m,"http://canacopegdl.com/images/cold/cold-14.jpg",
1
125
                             my_data->server_settings->viberReceiver.at(1),
1
126
                             my_data->server_settings->viberSender);
1
127
            postOnFacebook(m,"http://canacopegdl.com/images/cold/cold-14.jpg");
1
128
        }
1
129
        else {
1
130
            sendViberMsg(m,my_data->server_settings->viberReceiver.at(0),
1
131
                         my_data->server_settings->viberSender);
1
132
        }
2
133
    }
8
134
    else{
8
135
        //my_data->myEventHandler.run("unknown")->addEvent("temperatura nie przeszla przez "+to_string_with_precision(reference));
8
136
    }
14
137
}
138
139
std::string iDomTOOLS::getThermoStats(const std::string& name)
0
140
{
0
141
    return  allThermometerUpdate.getStatsByName(name);
0
142
}
143
144
void iDomTOOLS::updateTemperatureStats()
0
145
{
0
146
    auto v = getTemperature();
0
147
    allThermometerUpdate.updateAll(&v);
0
148
    allThermometerUpdate.updateStats("outside");
0
149
    allThermometerUpdate.updateStats("inside");
0
150
0
151
    if( true == allThermometerUpdate.isMoreDiff("outside",2.1)){
0
152
        auto  data = allThermometerUpdate.getLast2("outside");
0
153
        std::string msg = "alarm roznicy temeratur na polu! " + to_string_with_precision(data.first) +" na "+
0
154
                to_string_with_precision(data.second);
0
155
0
156
        if (data.first > data.second){
0
157
            msg += " temperatura maleje " + EMOJI::emoji(E_emoji::CHART_WITH_DOWNWARDS_TREND);
0
158
        }
0
159
        else{
0
160
            msg += " temperatura rośnie " + EMOJI::emoji(E_emoji::CHART_WITH_UPWARDS_TREND);
0
161
        }
0
162
0
163
        sendViberMsg(msg  ,
0
164
                     my_data->server_settings->viberReceiver.at(0),
0
165
                     my_data->server_settings->viberSender);
0
166
#ifndef BT_TEST
167
        log_file_mutex.mutex_lock();
168
        log_file_cout << WARNING << msg << std::endl;
169
        log_file_mutex.mutex_unlock();
170
#endif
0
171
    }
0
172
    if( true == allThermometerUpdate.isMoreDiff("inside",2.1)){
0
173
        auto  data = allThermometerUpdate.getLast2("inside");
0
174
        std::string msg = "alarm roznicy temeratur na mieszkaniu! " + to_string_with_precision(data.first) +" na "+
0
175
                to_string_with_precision(data.second);
0
176
0
177
        if (data.first > data.second){
0
178
            msg += " temperatura maleje " + EMOJI::emoji(E_emoji::CHART_WITH_DOWNWARDS_TREND);
0
179
        }
0
180
        else{
0
181
            msg += " temperatura rośnie " + EMOJI::emoji(E_emoji::CHART_WITH_UPWARDS_TREND);
0
182
        }
0
183
0
184
        sendViberMsg(msg  ,
0
185
                     my_data->server_settings->viberReceiver.at(0),
0
186
                     my_data->server_settings->viberSender);
0
187
#ifndef BT_TEST
188
        log_file_mutex.mutex_lock();
189
        log_file_cout << WARNING << msg << std::endl;
190
        log_file_mutex.mutex_unlock();
191
#endif
0
192
    }
0
193
}
194
195
void iDomTOOLS::turnOnSpeakers()
1
196
{
1
197
    if (useful_F::myStaticData->idom_all_state.houseState == STATE::UNLOCK)
0
198
    {
0
199
        digitalWrite(iDomConst::GPIO_SPIK, HIGH);
0
200
        useful_F::myStaticData->main_iDomStatus->setObjectState("speakers",STATE::ON);
0
201
    }
1
202
    else{
1
203
        useful_F::myStaticData->myEventHandler.run("speakers")->addEvent("speakers can not start due to home state: "+
1
204
                                                                         stateToString(useful_F::myStaticData->idom_all_state.houseState));
1
205
    }
1
206
    useful_F::myStaticData->main_iDomTools->saveState_iDom();
1
207
}
208
209
void iDomTOOLS::turnOffSpeakers()
0
210
{
0
211
    digitalWrite(iDomConst::GPIO_SPIK, LOW);
0
212
    useful_F::myStaticData->main_iDomStatus->setObjectState("speakers",STATE::OFF);
0
213
    // useful_F::myStaticData->main_iDomTools->saveState_iDom();
0
214
}
215
216
void iDomTOOLS::turnOnPrinter()
0
217
{
0
218
    if (my_data->idom_all_state.houseState == STATE::UNLOCK)
0
219
    {
0
220
        digitalWrite(iDomConst::GPIO_PRINTER,HIGH);
0
221
        my_data->myEventHandler.run("230V")->addEvent("230v drukarki ON");
0
222
        my_data->main_iDomStatus->setObjectState("printer",STATE::ON);
0
223
    }
0
224
    else{
0
225
        my_data->myEventHandler.run("230V")->addEvent("Printer can not start due to home state: "+
0
226
                                                      stateToString(my_data->idom_all_state.houseState));
0
227
    }
0
228
}
229
230
void iDomTOOLS::turnOffPrinter()
3
231
{
3
232
    digitalWrite(iDomConst::GPIO_PRINTER,LOW);
3
233
    my_data->myEventHandler.run("230V")->addEvent("230v drukarki OFF");
3
234
    my_data->main_iDomStatus->setObjectState("printer",STATE::OFF);
3
235
}
236
237
PIN_STATE iDomTOOLS::getPinState(int pin_number)
0
238
{
0
239
    int pin_state = digitalRead(pin_number);
0
240
0
241
    switch (pin_state){
0
242
    case 0:
0
243
        return PIN_STATE::LOW_STATE;
0
244
    case 1:
0
245
        return PIN_STATE::HIGH_STATE;
0
246
    default:
0
247
        return PIN_STATE::UNKNOWN_STATE;
0
248
    }
0
249
}
250
251
void iDomTOOLS::turnOnOffPrinter()
0
252
{
0
253
    PIN_STATE pinState = getPinState(iDomConst::GPIO_PRINTER);
0
254
    switch (pinState){
0
255
    case PIN_STATE::HIGH_STATE:
0
256
        turnOffPrinter();
0
257
        my_data->mainLCD->set_lcd_STATE(10);
0
258
        my_data->mainLCD->printString(true,0,0,"230V OFF");
0
259
        break;
0
260
    case PIN_STATE::LOW_STATE:
0
261
        turnOnPrinter();
0
262
        my_data->mainLCD->set_lcd_STATE(10);
0
263
        my_data->mainLCD->printString(true,0,0,"230V ON");
0
264
        break;
0
265
    default:
0
266
        puts("def");
0
267
#ifndef BT_TEST
268
        log_file_mutex.mutex_lock();
269
        log_file_cout << CRITICAL << " blad odczytu stanu pinu zasilania drukarki "<<   std::endl;
270
        log_file_mutex.mutex_unlock();
271
#endif
0
272
    }
0
273
}
274
275
void iDomTOOLS::turnOnOff433MHzSwitch(const std::string& name)
0
276
{
0
277
    STATE listwaState = my_data->main_iDomStatus->getObjectState(name);
0
278
    RADIO_SWITCH *m_switch = dynamic_cast<RADIO_SWITCH*>(my_data->main_REC->getEqPointer(name));
0
279
    if (listwaState == STATE::ON){
0
280
        my_data->mainLCD->set_lcd_STATE(10);
0
281
        my_data->mainLCD->printString(true,0,0,"230V OFF "+name);
0
282
        m_switch->off();
0
283
    }
0
284
    else if (listwaState == STATE::OFF){
0
285
        my_data->mainLCD->set_lcd_STATE(10);
0
286
        my_data->mainLCD->printString(true,0,0,"230V ON "+name);
0
287
        m_switch->on();
0
288
    }
0
289
    saveState_iDom();
0
290
}
291
292
void iDomTOOLS::turnOn433MHzSwitch(std::string name)
1
293
{
1
294
    RADIO_SWITCH *m_switch = dynamic_cast<RADIO_SWITCH*>(my_data->main_REC->getEqPointer(std::move(name)));
1
295
    m_switch->on();
1
296
    //saveState_iDom();
1
297
}
298
299
void iDomTOOLS::turnOff433MHzSwitch(std::string name)
1
300
{
1
301
    RADIO_SWITCH *m_switch = dynamic_cast<RADIO_SWITCH*>(my_data->main_REC->getEqPointer(std::move(name)));
1
302
    m_switch->off();
1
303
    //saveState_iDom();
1
304
}
305
306
void iDomTOOLS::runOnSunset()
0
307
{
0
308
    if (my_data->idom_all_state.houseState == STATE::UNLOCK)
0
309
    {
0
310
        ////switch 433mhz
0
311
        for (auto m_switch : my_data->main_REC->getSwitchPointerVector()){
0
312
            m_switch->onSunset();
0
313
        }
0
314
    }
0
315
    else{
0
316
        my_data->myEventHandler.run("iDom")->addEvent("433MHz can not start due to home state: "+
0
317
                                                        stateToString(my_data->idom_all_state.houseState));
0
318
    }
0
319
}
320
321
void iDomTOOLS::runOnSunrise()
0
322
{
0
323
    if (my_data->idom_all_state.houseState == STATE::UNLOCK)
0
324
    {
0
325
        ////switch 433mhz
0
326
        for (auto m_switch : my_data->main_REC->getSwitchPointerVector()){
0
327
            m_switch->onSunrise();
0
328
        }
0
329
    }
0
330
    else{
0
331
        my_data->myEventHandler.run("iDom")->addEvent("433MHz can not start due to home state: "+
0
332
                                                        stateToString(my_data->idom_all_state.houseState));
0
333
    }
0
334
    my_data->main_iDomTools->ledOFF();
0
335
}
336
337
void iDomTOOLS::lockHome()
6
338
{
6
339
    my_data->idom_all_state.houseState = STATE::LOCK;
6
340
    my_data->main_iDomStatus->setObjectState("house", STATE::LOCK);
6
341
    my_data->main_iDomTools->sendViberPicture("dom zablokownay!",
6
342
                                              "http://cyniu88.no-ip.pl/images/iDom/iDom/lock.jpg",
6
343
                                              my_data->server_settings->viberReceiver.at(0),
6
344
                                              my_data->server_settings->viberSender);
6
345
#ifndef BT_TEST
346
    log_file_mutex.mutex_lock();
347
    log_file_cout << INFO << "status domu - "+stateToString(my_data->idom_all_state.houseState)<<   std::endl;
348
    log_file_mutex.mutex_unlock();
349
#endif
6
350
    saveState_iDom();
6
351
}
352
353
void iDomTOOLS::unlockHome()
7
354
{
7
355
    my_data->idom_all_state.houseState = STATE::UNLOCK;
7
356
    my_data->main_iDomStatus->setObjectState("house", STATE::UNLOCK);
7
357
    my_data->main_iDomTools->sendViberPicture("dom odblokownay!",
7
358
                                              "http://cyniu88.no-ip.pl/images/iDom/iDom/unlock.jpg",
7
359
                                              my_data->server_settings->viberReceiver.at(0),
7
360
                                              my_data->server_settings->viberSender);
7
361
#ifndef BT_TEST
362
    log_file_mutex.mutex_lock();
363
    log_file_cout << INFO << "status domu - "+stateToString(my_data->idom_all_state.houseState)<<   std::endl;
364
    log_file_mutex.mutex_unlock();
365
#endif
7
366
    saveState_iDom();
7
367
}
368
369
void iDomTOOLS::switchActionOnLockHome()
1
370
{
1
371
    ////switch 433mhz
5
372
    for (auto m_switch : my_data->main_REC->getSwitchPointerVector()){
5
373
        m_switch->onLockHome();
5
374
    }
1
375
}
376
377
void iDomTOOLS::switchActionOnUnlockHome()
1
378
{
1
379
    ////switch 433mhz
5
380
    for (auto m_switch : my_data->main_REC->getSwitchPointerVector()){
5
381
        m_switch->onUnlockHome();
5
382
    }
1
383
}
384
385
std::string iDomTOOLS::buttonPressed(const std::string& id)
2
386
{
2
387
    for (auto n : buttonPointerVector){
2
388
        if (id == n->getID()){
1
389
            return n->getName();
1
390
        }
2
391
    }
1
392
    throw "UNKNOWN BUTTON ID: " + std::to_string(id);
2
393
}
394
395
void iDomTOOLS::button433MHzPressedAction(const std::string& name)
4
396
{
4
397
    if (name == "locker"){
4
398
        RADIO_BUTTON* buttonLocker = static_cast<RADIO_BUTTON*>(my_data->main_REC->getEqPointer(name) );
4
399
        button433mhzLockerPressed(buttonLocker);
4
400
    }
4
401
}
402
403
void iDomTOOLS::button433mhzLockerPressed(RADIO_BUTTON *radioButton)
10
404
{
10
405
    static unsigned int counter = 0;
10
406
10
407
    Clock t  = Clock::getTime();
10
408
    if (lastButton433MHzLockUnlockTime != t /*|| (lastButton433MHzLockUnlockTime + Clock(0,1)) == t*/)
6
409
    {
6
410
        //#ifdef BT_TEST
6
411
        std::cout << "LOCKER TEST iDomTOOLS::button433mhzLockerPressed()" <<std::endl;
6
412
        //#endif
6
413
        lastButton433MHzLockUnlockTime = t;
6
414
        counter = 0;
6
415
        if(my_data->idom_all_state.houseState != STATE::UNLOCK)
2
416
        {
2
417
            buttonUnlockHome();
2
418
            puts("\nodblokuje dom\n");
2
419
            radioButton->setState(STATE::UNLOCK);
2
420
        }
4
421
        else if (my_data->main_iDomStatus->getObjectState("music") == STATE::PLAY)
1
422
        {
1
423
            ledOFF();
1
424
            MPD_stop();
1
425
            turnOffPrinter();
1
426
            radioButton->setState(STATE::STOP);
1
427
            switchActionOnLockHome();
1
428
            //TODO  dodać wylaczanie wiatraka
1
429
        }
3
430
        else if (my_data->main_iDomStatus->getObjectState("music") == STATE::STOP)
1
431
        {
1
432
            MPD_play(my_data);
1
433
            switchActionOnUnlockHome();
1
434
            if(isItDay() == false)
1
435
            {
1
436
                ledOn(my_data->ptr_pilot_led->colorLED[2]);
1
437
            }
1
438
            radioButton->setState(STATE::PLAY);
1
439
        }
6
440
    }
10
441
    else
4
442
    {
4
443
        ++counter;
4
444
        if (counter == 2)
2
445
        {
2
446
            buttonLockHome();
2
447
            puts("\nzablokuje dom\n");
2
448
            radioButton->setState(STATE::LOCK);
2
449
        }
4
450
        //#ifdef BT_TEST
4
451
        std::cout << "LOCKER TEST iDomTOOLS::button433mhzLockerPressed()- counter: "<<counter <<std::endl;
4
452
        //#endif
4
453
    }
10
454
10
455
}
456
457
void iDomTOOLS::buttonLockHome()
2
458
{
2
459
    ledOFF();
2
460
    MPD_stop();
2
461
    turnOffPrinter();
2
462
    lockHome();
2
463
}
464
465
void iDomTOOLS::buttonUnlockHome()
2
466
{
2
467
    unlockHome();
2
468
    MPD_play(my_data);
2
469
    if(isItDay() == false){
2
470
        ledOn(my_data->ptr_pilot_led->colorLED[2]);
2
471
    }
2
472
}
473
474
bool iDomTOOLS::isItDay()
13
475
{
13
476
    Clock now = Clock::getTime();
13
477
    if(now < iDomTOOLS::getSunriseClock() || now > iDomTOOLS::getSunsetClock()){
13
478
        return false;
13
479
    }
0
480
    return true;
13
481
}
482
483
CARDINAL_DIRECTIONS::ALARM_INFO iDomTOOLS::getLightningStruct()
2
484
{
2
485
    std::lock_guard<std::mutex>  lock(m_lightningMutex);
2
486
    return m_lightningStruct;
2
487
}
488
489
void iDomTOOLS::setLightningStruct(CARDINAL_DIRECTIONS::ALARM_INFO &s)
2
490
{
2
491
    std::lock_guard<std::mutex>  lock(m_lightningMutex);
2
492
    //std::cout <<"struktura setowana " << s.data.str() <<std::endl;
2
493
    m_lightningStruct = s;
2
494
2
495
    //std::cout <<"struktura już po setowaniu " << m_lightningStruct.data.str() <<std::endl;
2
496
}
497
498
void iDomTOOLS::checkLightning()
1
499
{
1
500
    nlohmann::json jj = useful_F_libs::getJson(my_data->server_settings->lightningApiURL);
1
501
1
502
    CARDINAL_DIRECTIONS::ALARM_INFO lightningData = lightning.lightningAlert(jj);
1
503
    setLightningStruct(lightningData);
1
504
    bool result = lightning.checkLightningAlert(&lightningData);
1
505
1
506
    if(result == true)
1
507
    {
1
508
1
509
        m_viber.setAvatar("http://cyniu88.no-ip.pl/avatar/lightning.jpg");
1
510
        STATE stateMSG = sendViberMsgBool("UWAGA BURZA KOŁO KRAKOWA! "+EMOJI::emoji(E_emoji::THUNDER_CLOUD_AND_RAIN)
1
511
                                          +"\\n\\n "+lightningData.data.str() ,
1
512
                                          my_data->server_settings->viberReceiver.at(0),
1
513
                                          my_data->server_settings->viberSender);
1
514
1
515
        stateMSG = sendViberMsgBool("UWAGA BURZA KOŁO KRAKOWA! "+EMOJI::emoji(E_emoji::THUNDER_CLOUD_AND_RAIN)
1
516
                                    +"\\n\\n "+lightningData.data.str() ,
1
517
                                    my_data->server_settings->viberReceiver.at(1),
1
518
                                    my_data->server_settings->viberSender);
1
519
1
520
        m_viber.setAvatar(my_data->server_settings->viberAvatar);
1
521
        if(stateMSG == STATE::SEND_OK)
0
522
        {
0
523
#ifndef BT_TEST
524
            log_file_mutex.mutex_lock();
525
            log_file_cout << INFO << "wysłano informacje o burzy"<< std::endl;
526
            log_file_mutex.mutex_unlock();
527
#endif
0
528
        }
1
529
        else
1
530
        {
1
531
#ifndef BT_TEST
532
            log_file_mutex.mutex_lock();
533
            log_file_cout << ERROR << "nie wysłano informacje o burzy"<< std::endl;
534
            log_file_mutex.mutex_unlock();
535
#endif
1
536
        }
1
537
    }
1
538
}
539
540
std::string iDomTOOLS::getSunrise(bool extend )
0
541
{
0
542
    Clock tt = sun.getSunRise();
0
543
    if (extend == true){
0
544
        return "Sunrise time: "+tt.getString();
0
545
    }
0
546
    return tt.getString();
0
547
}
548
549
std::string iDomTOOLS::getSunset(bool extend )
0
550
{
0
551
    Clock tt = sun.getSunSet();
0
552
    if (extend == true){
0
553
        return  "Sunset time: "+tt.getString();
0
554
    }
0
555
    return tt.getString();
0
556
}
557
558
Clock iDomTOOLS::getSunsetClock()
13
559
{
13
560
    return sun.getSunSet();
13
561
}
562
563
Clock iDomTOOLS::getSunriseClock()
13
564
{
13
565
    return sun.getSunRise();
13
566
}
567
568
std::string iDomTOOLS::getDayLenght(bool extend )
0
569
{
0
570
    Clock tt = sun.getDayLength();
0
571
    if (extend == true){
0
572
        return "Day Lenght : "+tt.getString();
0
573
    }
0
574
    return tt.getString();
0
575
}
576
577
std::string iDomTOOLS::getWeatherEvent(const std::string& city, unsigned int radius)
0
578
{
0
579
    std::string url = "http://burze.dzis.net/ramka.php?miejscowosc=";
0
580
    url.append(city);
0
581
    url.append("&promien=");
0
582
    url.append(std::to_string(radius));
0
583
    return useful_F_libs::httpPost(url, 10);
0
584
}
585
586
std::vector<WEATHER_ALER> iDomTOOLS::getAlert(std::string data)
1
587
{
1
588
    std::vector<WEATHER_ALER> wAlert;
1
589
    WEATHER_ALER tempWA;
1
590
    std::string d = useful_F_libs::removeHtmlTag(data);
1
591
    std::vector<std::string> vect;
1
592
1
593
    vect =  useful_F::split(d,'\n');
1
594
    vect.pop_back();
1
595
    for (auto n : vect)
7
596
    {
7
597
        if (n.find("brak") == std::string::npos)
1
598
        {
1
599
            tempWA.alert = n;
1
600
            tempWA.name = n;
1
601
            tempWA.sended = false;
1
602
            wAlert.push_back(tempWA);
1
603
        }
7
604
    }
1
605
    return {wAlert};
1
606
}
607
608
void iDomTOOLS::textToSpeach(std::vector<std::string> *textVector)
0
609
{
0
610
    if (textVector->empty() ){
0
611
        return;
0
612
    }
0
613
    std::string txt;
0
614
0
615
    for (auto a : *textVector){
0
616
        txt += a;
0
617
    }
0
618
    /////////// start thread  TTS - python use ////////////////////////
0
619
    std::string command = " python /home/pi/programowanie/iDom_server_OOP/script/PYTHON/gadacz.py ";
0
620
    command += "\""+ txt +"\"";
0
621
    if(my_data->ptr_MPD_info->isPlay){
0
622
0
623
    }
0
624
    else {
0
625
        turnOnSpeakers();
0
626
    }
0
627
    system(command.c_str());
0
628
    if(my_data->ptr_MPD_info->isPlay){
0
629
0
630
    }
0
631
    else {
0
632
        turnOffSpeakers();
0
633
    }
0
634
}
635
636
std::string iDomTOOLS::getTextToSpeach()
0
637
{
0
638
    std::vector<std::string> dayL = useful_F::split(getDayLenght(),':');
0
639
    std::stringstream  text;
0
640
    std::string smogText = getSmog();
0
641
    int smogInt = std::stoi(smogText);
0
642
    text <<  "Godzina: " << Clock::getTime().getString();
0
643
    text << ". \nWschód słońca: " << getSunrise();
0
644
    text << ". \nZachód słońca: " << getSunset();
0
645
    text << ". \nDługość dnia: " << dayL[0] << " godzin " << dayL[1] << " minut";
0
646
    text <<". \n";
0
647
    dayL = getTemperature();
0
648
    text << "Temperatura na zewnątrz: " << dayL[1] << " stopnia. \n";
0
649
    text << "Temperatura w pokoju: " << dayL[0] << " stopnia. \n";
0
650
    text << "Smog: " << smogText << " mg/m^3. \n";
0
651
    if (smogInt > 50){
0
652
        int result = smogInt *2 ;
0
653
        text << "UWAGA! Maksymalna wartość przekroczona " << result << "%.";
0
654
    }
0
655
    return text.str();
0
656
}
657
658
std::vector<std::string> iDomTOOLS::getTemperature()
7
659
{
7
660
    std::vector<std::string>  vect = useful_F::split(useful_F::send_to_arduino(my_data,"temperature:22;"),':');
7
661
    return vect;
7
662
}
663
664
std::string iDomTOOLS::getTemperatureString()
0
665
{
0
666
    return useful_F::send_to_arduino(my_data,"temperature:22;");
0
667
}
668
669
std::string iDomTOOLS::getSmog()
8
670
{
8
671
    CURL *curl;
8
672
    CURLcode res;
8
673
    std::string readBuffer;
8
674
    curl = curl_easy_init();
8
675
8
676
    if(curl) {
8
677
        curl_easy_setopt(curl, CURLOPT_URL, "www.smog.krakow.pl");
8
678
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, useful_F_libs::WriteCallback);
8
679
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
8
680
        res = curl_easy_perform(curl);
8
681
        /* Check for errors */
8
682
        if(res != CURLE_OK)
0
683
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
0
684
                    curl_easy_strerror(res));
8
685
8
686
        /* always cleanup */
8
687
        curl_easy_cleanup(curl);
8
688
    }
8
689
    curl_global_cleanup();
8
690
    int start = readBuffer.find("<h2 class=\"polution\">");
8
691
    try {
8
692
        readBuffer = readBuffer.substr(start, 40);
8
693
    }
0
694
    catch (...){
0
695
#ifndef BT_TEST
696
        log_file_mutex.mutex_lock();
697
        log_file_cout << CRITICAL << "wyjatek substr() e getSmog() !!!!!!"<< std::endl;
698
        log_file_mutex.mutex_unlock();
699
#endif
0
700
    }
8
701
8
702
    readBuffer = useful_F_libs::find_tag(readBuffer);
8
703
8
704
    return readBuffer;
8
705
}
706
707
void iDomTOOLS::send_temperature_thingSpeak()
7
708
{
7
709
    std::vector<std::string> _temperature = getTemperature();
7
710
    std::string addres = "api.thingspeak.com/update?key=";
7
711
    addres+=key;
7
712
    addres+="&field1=";
7
713
    addres+= _temperature.at(0);
7
714
    // addres.erase(addres.size()-2,addres.size());
7
715
    addres+= "&field3="+_temperature.at(1);
7
716
    addres+="&field2="+getSmog();
7
717
    //////////////////////////////// pozyskanie temperatury
7
718
    allThermometer.updateAll(&_temperature);
7
719
    sendSMSifTempChanged("outside",0);
7
720
    sendSMSifTempChanged("inside",24);
7
721
    std::string s = useful_F_libs::httpPost(addres,10);
7
722
7
723
    if(s == "0"){
0
724
#ifndef BT_TEST
725
        log_file_mutex.mutex_lock();
726
        log_file_cout << CRITICAL << " błąd wysyłania temoeratury na thingspeak: "<< s <<   std::endl;
727
        log_file_mutex.mutex_unlock();
728
#endif
0
729
    }
7
730
}
731
732
std::string iDomTOOLS::sendSMStoPlusGSM(const std::string &login, const std::string &pass, const std::string &number,
733
                                        std::string msg, int silentFrom , int silentTo  )
0
734
{
0
735
    if (silentFrom !=0 && silentTo !=0){
0
736
        // TODO
0
737
    }
0
738
    std::replace(msg.begin(),msg.end(),' ','+');
0
739
    std::string address = "http://darsonserver.5v.pl/bramkaPlus?login=";
0
740
    address +=login+"&password="+pass+"&sender=iDom&number="+number+"&message="+msg;
0
741
0
742
    std::string readBuffer = useful_F_libs::httpPost(address,10);
0
743
0
744
#ifndef BT_TEST
745
    log_file_mutex.mutex_lock();
746
    log_file_cout << INFO <<"wysłano SMSa otreśći: " <<  msg<<std::endl;
747
    log_file_mutex.mutex_unlock();
748
#endif
0
749
    return readBuffer +"\n"+address;
0
750
}
751
752
void iDomTOOLS::cameraLedON(const std::string& link)
0
753
{
0
754
    Clock t = Clock::getTime();
0
755
    SunRiseSet sun;
0
756
    Clock sunRise, sunSet;
0
757
    sunRise = sun.getSunRise();
0
758
    sunSet = sun.getSunSet();
0
759
    sunSet += Clock(23,30); // +23:30 == -00:30
0
760
    if (t <= sunRise || t >= sunSet){
0
761
        //printf("zapalam leda!\n");
0
762
        std::string s = useful_F_libs::httpPost(link,10);
0
763
        if (s == "ok.\n"){
0
764
            my_data->main_iDomStatus->setObjectState("cameraLED",STATE::ON);
0
765
            //  printf("w ifie\n");
0
766
        }
0
767
    }
0
768
    // printf("nie odpalam leda!\n");
0
769
}
770
771
void iDomTOOLS::cameraLedOFF(const std::string& link)
0
772
{
0
773
    std::string s = useful_F_libs::httpPost(link,10);
0
774
    //printf (" camera response '%s' \n", s.c_str());
0
775
    if (s == "ok.\n"){
0
776
        my_data->main_iDomStatus->setObjectState("cameraLED",STATE::OFF);
0
777
        //printf("w ifie\n");
0
778
    }
0
779
}
780
781
nlohmann::json iDomTOOLS::sendViberMsg(const std::string &msg,
782
                                       const std::string &receiver,
783
                                       const std::string &senderName,
784
                                       const std::string& accessToken,
785
                                       const std::string& url)
8
786
{
8
787
    nlohmann::json jj;
8
788
    std::lock_guard<std::mutex>  lock(m_msgMutex);
8
789
    jj = nlohmann::json::parse( m_viber.sendViberMSG(msg,receiver,senderName,accessToken,url));
8
790
    return jj;
8
791
}
792
793
nlohmann::json iDomTOOLS::sendViberPicture(const std::string &msg,
794
                                           const std::string &image,
795
                                           const std::string &receiver,
796
                                           const std::string &senderName,
797
                                           const std::string& accessToken,
798
                                           const std::string& url)
15
799
{
15
800
    nlohmann::json jj;
15
801
    std::lock_guard<std::mutex>  lock(m_msgMutex);
15
802
    jj = nlohmann::json::parse(m_viber.sendViberPicture(msg,image,receiver,senderName,accessToken,url));
15
803
    return jj;
15
804
}
805
806
STATE iDomTOOLS::sendViberMsgBool(const std::string &msg,
807
                                  const std::string &receiver,
808
                                  const std::string &senderName,
809
                                  const std::string& accessToken,
810
                                  const std::string& url)
2
811
{
2
812
    nlohmann::json jj = sendViberMsg(msg,receiver,senderName,accessToken,url);
2
813
    STATE ret = STATE::SEND_NOK;
2
814
    if(jj.find("status_message")!= jj.end())
0
815
    {
0
816
        if(jj.at("status_message").get<std::string>() == "ok")
0
817
        {
0
818
            ret = STATE::SEND_OK;
0
819
        }
0
820
    }
2
821
    else
2
822
    {
2
823
#ifndef BT_TEST
824
        log_file_mutex.mutex_lock();
825
        log_file_cout << ERROR << "nie wyslanno wiadomosci viber"<< jj.dump()<< std::endl;
826
        log_file_mutex.mutex_unlock();
827
#endif
2
828
    }
2
829
    return ret;
2
830
}
831
832
STATE iDomTOOLS::sendViberPictureBool(const std::string& msg,
833
                                      const std::string& image,
834
                                      const std::string& receiver,
835
                                      const std::string& senderName,
836
                                      const std::string& accessToken,
837
                                      const std::string& url)
0
838
{
0
839
    nlohmann::json jj = sendViberPicture(msg,image,receiver,senderName,accessToken,url);
0
840
    STATE ret = STATE::SEND_NOK;
0
841
    if(jj.at("status_message").get<std::string>() == "ok")
0
842
    {
0
843
        ret = STATE::SEND_OK;
0
844
    }
0
845
    else
0
846
    {
0
847
#ifndef BT_TEST
848
        log_file_mutex.mutex_lock();
849
        log_file_cout << ERROR << "nie wyslanno wiadomosci viber"<< jj.dump()<< std::endl;
850
        log_file_mutex.mutex_unlock();
851
#endif
0
852
    }
0
853
    return ret;
0
854
}
855
856
std::string iDomTOOLS::postOnFacebook(const std::string& msg, const std::string& image)
1
857
{
1
858
    std::lock_guard<std::mutex>  lock(m_msgMutex);
1
859
    if (image != "NULL"){
1
860
        return m_facebook.postPhotoOnWall(image,msg);
1
861
    }
1
862
0
863
    return  m_facebook.postTxtOnWall(msg);
1
864
}
865
866
std::string iDomTOOLS::ledOFF()
4
867
{
4
868
    return useful_F::send_to_arduino(my_data,"LED_STOP:2;");
4
869
}
870
871
std::string iDomTOOLS::ledClear()
0
872
{
0
873
    return useful_F::send_to_arduino(my_data,"LED_CLEAR:2;");
0
874
}
875
876
std::string iDomTOOLS::ledClear(unsigned int from, unsigned int to)
10
877
{
10
878
    LED_Strip ledColor(0,60,0,0,0,"BLACK");
10
879
    useful_F::send_to_arduino(my_data,ledColor.get(from, to));
10
880
    return "Led cleared";
10
881
}
882
883
std::string iDomTOOLS::ledOn(const LED_Strip& ledColor, unsigned int from, unsigned int to)
12
884
{
12
885
    if (my_data->idom_all_state.houseState == STATE::UNLOCK)
3
886
    {
3
887
        return useful_F::send_to_arduino(my_data,ledColor.get(from, to));
3
888
    }
9
889
    else{
9
890
        my_data->myEventHandler.run("LED")->addEvent("LED can not start due to home state: "+
9
891
                                                     stateToString(my_data->idom_all_state.houseState));
9
892
    }
9
893
    return "iDom LOCKED!";
12
894
}
895
896
void iDomTOOLS::checkAlarm()
10
897
{
10
898
    unsigned int fromVol = my_data->alarmTime.fromVolume;
10
899
    unsigned int   toVol = my_data->alarmTime.toVolume;
10
900
    unsigned int radioId = my_data->alarmTime.radioID;
10
901
10
902
    Clock now = Clock::getTime();
10
903
10
904
    if (now == my_data->alarmTime.time && my_data->alarmTime.state == STATE::ACTIVE){
1
905
        my_data->alarmTime.state = STATE::WORKING;
1
906
        MPD_volumeSet(my_data, fromVol);
1
907
        MPD_play(my_data,radioId);
1
908
        my_data->main_iDomStatus->setObjectState("alarm",STATE::DEACTIVE);
1
909
    }
10
910
10
911
    if (my_data->alarmTime.state == STATE::WORKING){
10
912
        unsigned int vol = MPD_getVolume(my_data) + 1;
10
913
        if (vol < toVol){
9
914
            MPD_volumeSet(my_data, vol);
9
915
9
916
            if(iDomTOOLS::isItDay() == false){
9
917
                my_data->main_iDomTools->ledOn(my_data->ptr_pilot_led->colorLED[2],fromVol,vol);
9
918
            }
9
919
        }
1
920
        else{
1
921
            my_data->alarmTime.state = STATE::DEACTIVE;
1
922
            if(iDomTOOLS::isItDay() == false){
1
923
                my_data->main_iDomTools->turnOn433MHzSwitch("ALARM");
1
924
            }
1
925
        }
10
926
    }
10
927
}
928
929
void iDomTOOLS::saveState_iDom()
16
930
{
16
931
    iDom_SAVE_STATE info(my_data->server_settings->saveFilePath);
16
932
    nlohmann::json jsonAlarm;
16
933
    nlohmann::json jsonMPD;
16
934
    nlohmann::json json_iDomLOCK;
16
935
    nlohmann::json json433Mhz;
16
936
    //////////////////// iDom
16
937
    json_iDomLOCK["iDomLock"] = stateToString(my_data->idom_all_state.houseState);
16
938
    //////////////////// alarm
16
939
    jsonAlarm["alarm"] = my_data->main_iDomStatus->getObjectStateString("alarm");
16
940
    jsonAlarm["time"]  = my_data->alarmTime.time.getString();
16
941
    jsonAlarm["fromVolume"] = my_data->alarmTime.fromVolume;
16
942
    jsonAlarm["toVolume"] = my_data->alarmTime.toVolume;
16
943
    jsonAlarm["radioID"] = my_data->alarmTime.radioID;
16
944
    //////////////////// mpd
16
945
    jsonMPD["music"] = my_data->main_iDomStatus->getObjectStateString("music");
16
946
    jsonMPD["speakers"] = my_data->main_iDomStatus->getObjectStateString("speakers");
16
947
    ////////////////// 433Mhz
16
948
    auto switch433vector = my_data->main_REC->getSwitchPointerVector();
16
949
    for (auto v : switch433vector)
80
950
    {
80
951
        v->getName();
80
952
        json433Mhz[v->getName()] = stateToString(v->getState());
80
953
    }
16
954
    ///
16
955
    nlohmann::json json;
16
956
    json["iDom"] = json_iDomLOCK;
16
957
    json["ALARM"] = jsonAlarm;
16
958
    json["MPD"] = jsonMPD;
16
959
    json["433Mhz"] = json433Mhz;
16
960
16
961
    info.write(json);
16
962
#ifdef BT_TEST
16
963
    std::cout << json <<std::endl;
16
964
    std::cout << " saved to " << my_data->server_settings->saveFilePath <<std::endl;
16
965
#endif
16
966
}
967
968
void iDomTOOLS::readState_iDom()
1
969
{
1
970
    try
1
971
    {
1
972
        iDom_SAVE_STATE info(my_data->server_settings->saveFilePath);
1
973
        nlohmann::json jj = info.read();
1
974
#ifdef BT_TEST
1
975
        std::cout << "JSON: " << jj.dump(4) << std::endl;
1
976
#endif
1
977
        nlohmann::json json433MHz = jj.at("433Mhz");
1
978
6
979
        for (nlohmann::json::iterator it = json433MHz.begin(); it != json433MHz.end(); ++it)
5
980
        {
5
981
            if( it.value() == "ON"){
0
982
                my_data->main_iDomTools->turnOn433MHzSwitch(it.key());
0
983
            }
5
984
            else if ( it.value() == "OFF"){
0
985
                my_data->main_iDomTools->turnOff433MHzSwitch(it.key());
0
986
            }
5
987
        }
1
988
        auto iDomLock = jj.at("iDom").at("iDomLock").get<std::string>();
1
989
1
990
        if(iDomLock == "UNLOCK")
0
991
            unlockHome();
1
992
        else if (iDomLock == "LOCK")
1
993
            lockHome();
1
994
1
995
        auto mpdMusic = jj.at("MPD").at("music").get<std::string>();
1
996
        auto mpdSpeakers = jj.at("MPD").at("speakers").get<std::string>();
1
997
1
998
        if(mpdMusic == "PLAY")
1
999
            MPD_play(my_data);
0
1000
        else if(mpdMusic == "STOP")
0
1001
            MPD_stop();
1
1002
        if(mpdSpeakers == "ON")
1
1003
            turnOnSpeakers();
0
1004
        else if(mpdSpeakers == "OFF")
0
1005
            turnOffSpeakers();
1
1006
1
1007
        auto alarmState = jj.at("ALARM").at("alarm").get<std::string>();
1
1008
        auto alarmTime  = jj.at("ALARM").at("time").get<std::string>();
1
1009
        my_data->alarmTime.fromVolume = jj.at("ALARM").at("fromVolume").get<int>();
1
1010
        my_data->alarmTime.toVolume = jj.at("ALARM").at("toVolume").get<int>();
1
1011
        my_data->alarmTime.radioID = jj.at("ALARM").at("radioID").get<int>();
1
1012
1
1013
        if (alarmState == "ACTIVE"){
1
1014
            my_data->alarmTime.time = Clock(alarmTime);
1
1015
            my_data->alarmTime.state = STATE::ACTIVE;
1
1016
            my_data->main_iDomStatus->setObjectState("alarm", my_data->alarmTime.state);
1
1017
            saveState_iDom();
1
1018
        }
1
1019
    }
1
1020
    catch(...)
0
1021
    {
0
1022
#ifndef BT_TEST
1023
        log_file_mutex.mutex_lock();
1024
        log_file_cout << ERROR << "nie ma pliku json z stanem iDom"<< std::endl;
1025
        log_file_mutex.mutex_unlock();
1026
#endif
0
1027
#ifdef BT_TEST
0
1028
        std::cout << "nie ma pliku json z stanem iDom" << std::endl;
0
1029
#endif
0
1030
    }
1
1031
}
1032
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/idomtools_mpd.cpp
1
#include "idomtools.h"
2
#include "../blockQueue/blockqueue.h"
3
#include "../functions/functions.h"
4
5
void iDomTOOLS::MPD_play(thread_data* my_data)
6
6
{
6
7
    if(my_data->idom_all_state.houseState == STATE::UNLOCK)
4
8
    {
4
9
        blockQueue _q;
4
10
        _q._add(MPD_COMMAND::PLAY);
4
11
    }
6
12
    else
2
13
    {
2
14
        my_data->myEventHandler.run("MPD")->addEvent("MPD can not start due to home state: "+
2
15
                                                     stateToString(my_data->idom_all_state.houseState));
2
16
    }
6
17
}
18
19
void iDomTOOLS::MPD_stop()
5
20
{
5
21
    blockQueue _q;
5
22
    _q._add(MPD_COMMAND::STOP);
5
23
}
24
25
void iDomTOOLS::MPD_next()
0
26
{
0
27
    blockQueue _q;
0
28
    _q._add(MPD_COMMAND::NEXT);
0
29
}
30
31
void iDomTOOLS::MPD_prev()
0
32
{
0
33
    blockQueue _q;
0
34
    _q._add(MPD_COMMAND::PREV);
0
35
}
36
37
void iDomTOOLS::MPD_pause()
0
38
{
0
39
    blockQueue _q;
0
40
    _q._add(MPD_COMMAND::PAUSE);
0
41
}
42
43
void iDomTOOLS::MPD_volumeUp()
0
44
{
0
45
    blockQueue _q;
0
46
    _q._add(MPD_COMMAND::VOLUP);
0
47
}
48
49
void iDomTOOLS::MPD_volumeDown()
0
50
{
0
51
    blockQueue _q;
0
52
    _q._add(MPD_COMMAND::VOLDOWN);
0
53
}
54
55
void iDomTOOLS::MPD_volumeSet(thread_data *my_data, int vol)
10
56
{
10
57
    my_data->ptr_MPD_info->volume = vol;
10
58
    blockQueue _q;
10
59
    _q._add(MPD_COMMAND::VOLSET);
10
60
}
61
62
void iDomTOOLS::MPD_play(thread_data *my_data, int id)
1
63
{
1
64
    if(my_data->idom_all_state.houseState == STATE::UNLOCK)
0
65
    {
0
66
        my_data->ptr_MPD_info->currentSongID = id;
0
67
        blockQueue _q;
0
68
        _q._add(MPD_COMMAND::PLAY_ID);
0
69
    }
1
70
    else
1
71
    {
1
72
        my_data->myEventHandler.run("MPD")->addEvent("MPD can not start due to home state: "+
1
73
                                                     stateToString(my_data->idom_all_state.houseState));
1
74
    }
1
75
}
76
77
int iDomTOOLS::MPD_getVolume(thread_data *my_data)
10
78
{
10
79
    return my_data->ptr_MPD_info->volume;
10
80
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/idomtools_system.cpp
1
#include "idomtools.h"
2
#include <sys/sysinfo.h>
3
#include <sys/utsname.h>
4
#include <sys/resource.h>
5
#include <sys/time.h>
6
#include <unistd.h>
7
8
std::string iDomTOOLS::getSystemInfo()
1
9
{
1
10
    double load[3];
1
11
    if (getloadavg(load, 3) != -1)
1
12
    {
1
13
#ifdef BT_TEST
1
14
        printf("load average : %f , %f , %f\n", load[0],load[1],load[2]);
1
15
#endif
1
16
    }
1
17
    const double megabyte = 1024 * 1024;
1
18
    struct sysinfo info;
1
19
    sysinfo(&info);
1
20
1
21
    long input_seconds = info.uptime;
1
22
    auto days = input_seconds / 60 / 60 / 24;
1
23
    auto hours = (input_seconds / 60 / 60) % 24;
1
24
    auto minutes = (input_seconds / 60) % 60;
1
25
    auto seconds = input_seconds % 60;
1
26
1
27
    std::stringstream  ret;
1
28
    ret << "System uptime: " << days <<" day " << hours
1
29
        << " hours " << minutes << " minutes "
1
30
        << seconds << " seconds " << std::endl << "Load: "
1
31
        << (info.loads[0]/65536) << "% - 1 min, " <<(info.loads[1]/65536)
1
32
        << "% - 5 min, "<<(info.loads[2]/65536) << "% - 15 min." << std::endl
1
33
        << "process count : " << info.procs << std::endl
1
34
        << "total RAM   : "<< (info.totalram / megabyte)<< "MB" << std::endl
1
35
        << "free RAM   : " << (info.freeram / megabyte) << "MB" << std::endl;
1
36
1
37
    return ret.str();
1
38
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/lightning.cpp
1
#include "lightning.h"
2
3
LIGHTNING::LIGHTNING()
112
4
{
112
5
    puts("LIGHTNING::LIGHTNING()");
112
6
}
7
8
LIGHTNING::~LIGHTNING()
112
9
{
112
10
    puts("LIGHTNING::~LIGHTNING()");
112
11
}
12
13
CARDINAL_DIRECTIONS::ALARM_INFO LIGHTNING::lightningAlert(nlohmann::json jj)
13
14
{
13
15
    CARDINAL_DIRECTIONS::ALARM_INFO data;
13
16
    nlohmann::json i;
13
17
13
18
#ifdef BT_TEST
13
19
    std::cout <<"\n\n data all " << i.dump(4) <<" size:"<< i.size() <<std::endl;
13
20
#endif
13
21
    if (jj.find("response") != jj.end())
12
22
    {
12
23
        i = jj.at("response").get<nlohmann::json>();
12
24
    }
13
25
    else
1
26
    {
1
27
        std::cout << " zly JSON " <<std::endl;
1
28
        return data;
1
29
    }
13
30
12
31
    auto _size = i.size();
12
32
    if (_size == 0)
4
33
    {
4
34
        data.riseAlarm = false;
4
35
        return data;
4
36
    }
8
37
    STATISTIC<int> ageAver(_size);
8
38
    STATISTIC<double> distanceKmAver(_size);
8
39
    STATISTIC<int> bearingAver(_size);
146
40
    for (auto j : i){
146
41
#ifdef BT_TEST
146
42
   //     std::cout <<"\n distance " << j.at("relativeTo").at("bearingENG").get<std::string>() << std::endl;
146
43
   //     std::cout <<"distance " << j.at("relativeTo").at("distanceKM").get<double>() << std::endl;
146
44
   //     std::cout <<"timestamp " << j.at("age").get<int>() << std::endl;
146
45
#endif
146
46
        ageAver.push_back(j.at("age").get<int>());
146
47
        distanceKmAver.push_back(j.at("relativeTo").at("distanceKM").get<double>());
146
48
        bearingAver.push_back(static_cast<int>(CARDINAL_DIRECTIONS::stringToCardinalDirectionsEnum(
146
49
                                                   j.at("relativeTo").at("bearingENG").get<std::string>()))
146
50
                              );
146
51
    }
8
52
    data.bearingENG = static_cast<CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM>(bearingAver.mode());
8
53
    data.distance = distanceKmAver.average();
8
54
    data.timestamp = ageAver.median();
8
55
8
56
    data.data.str(std::string());
8
57
    data.data << "ilość uderzeń: "<< _size << "\\n";
8
58
    data.data << "średni czas upłynięty od ostatniego uderzenia pioruna: "<< data.timestamp << " sek \\n";
8
59
    data.data << "średnia odległość ostatniego uderzenia pieruna: "<< data.distance <<" km \\n ";
8
60
    data.data << "kierunek uderzeń piorunów: " << CARDINAL_DIRECTIONS::cardinalDirectionsEnumToHuman(data.bearingENG) ;
8
61
8
62
    if(i.size() > 0){
8
63
        // std::cout << "jest size: " << i.size()<<std::endl;
8
64
        data.riseAlarm = true;
8
65
    }
8
66
8
67
    return data;
12
68
}
69
70
bool LIGHTNING::checkLightningAlert(CARDINAL_DIRECTIONS::ALARM_INFO *info)
15
71
{
15
72
#ifdef BT_TEST
15
73
    std::cout << "LIGHTNING::checkLightningAlert() bool "<< info->riseAlarm <<" local " << alarmState << std::endl
15
74
              << " distance " << info->distance << std::endl;
15
75
#endif
15
76
    if(info->riseAlarm == false && alarmState == false){
4
77
#ifdef BT_TEST
4
78
        std::cout << "(info->riseAlarm == false || alarmState == false)"<<std::endl;
4
79
#endif
4
80
        return false;
4
81
    }
11
82
    if(info->riseAlarm == false && alarmState == true){
2
83
#ifdef BT_TEST
2
84
        std::cout << "(info->riseAlarm == false || alarmState == true)"<<std::endl;
2
85
#endif
2
86
        alarmState = false;
2
87
        return false;
2
88
    }
9
89
    if(info->riseAlarm == true && alarmState == false){
5
90
5
91
#ifdef BT_TEST
5
92
        std::cout << "(info->riseAlarm == true || alarmState == false)"<<std::endl;
5
93
#endif
5
94
        alarmState = true;
5
95
        lightningTime = Clock::getTime();
5
96
        oldDistance = info->distance;
5
97
        std::cout << " w true oldDistance: "<< oldDistance <<std::endl;
5
98
        return true;
5
99
    }
9
100
9
101
#ifdef BT_TEST
4
102
    std::cout << "checkLightningAlert() - dystans"<<std::endl;
4
103
    std::cout << "Dystans: " <<info->distance << " oldDistance: "<< oldDistance <<std::endl;
4
104
#endif
4
105
    if(oldDistance > info->distance)
1
106
    {
1
107
1
108
        oldDistance = info->distance;
1
109
        return true;
1
110
    }
4
111
    else
3
112
    {
3
113
        oldDistance = info->distance;
3
114
    }
4
115
    ////////////////clear
4
116
    //oldDistance = 0.0;
3
117
    return false;
4
118
}
119
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/lightning.h
1
#ifndef LIGHTNING_H
2
#define LIGHTNING_H
3
#include <iostream>
4
5
#include "../../libs/Statistic/statistic.h"
6
#include "../../libs/useful/useful.h"
7
8
#include "idomtools_useful.h"
9
#include "json.hpp"
10
11
class CARDINAL_DIRECTIONS{
12
public:
13
    enum class CARDINAL_DIRECTIONS_ENUM{
14
        /*
15
           N
16
        NNW NNE
17
      NW       NE
18
   WNW		     ENE
19
 W				    E
20
   WSW			 ESE
21
      SW	   SE
22
        SSW	 SSE
23
           S
24
    */
25
26
        N = 1,NNE,NE,ENE,E,ESE,SE,SSE,S,SSW,SW,WSW,W,WNW,NW,NNW,ERROR
27
    };
28
    static CARDINAL_DIRECTIONS_ENUM stringToCardinalDirectionsEnum(std::string s){
29
        if (s == "N")      return CARDINAL_DIRECTIONS_ENUM::N;
30
        else if (s == "NNE")    return CARDINAL_DIRECTIONS_ENUM::NNE;
31
        else if (s == "NE")     return CARDINAL_DIRECTIONS_ENUM::NE;
32
        else if (s == "ENE")    return CARDINAL_DIRECTIONS_ENUM::ENE;
33
        else if (s == "E")      return CARDINAL_DIRECTIONS_ENUM::E;
34
        else if (s == "ESE")    return CARDINAL_DIRECTIONS_ENUM::ESE;
35
        else if (s == "SE")     return CARDINAL_DIRECTIONS_ENUM::SE;
36
        else if (s == "SSE")    return CARDINAL_DIRECTIONS_ENUM::SSE;
37
        else if (s == "S")      return CARDINAL_DIRECTIONS_ENUM::S;
38
        else if (s == "SSW")    return CARDINAL_DIRECTIONS_ENUM::SSW;
39
        else if (s == "SW")     return CARDINAL_DIRECTIONS_ENUM::SW;
40
        else if (s == "WSW")    return CARDINAL_DIRECTIONS_ENUM::WSW;
41
        else if (s == "W")      return CARDINAL_DIRECTIONS_ENUM::W;
42
        else if (s == "WNW")    return CARDINAL_DIRECTIONS_ENUM::WNW;
43
        else if (s == "NW")     return CARDINAL_DIRECTIONS_ENUM::NW;
44
        else if (s == "NNW")    return CARDINAL_DIRECTIONS_ENUM::NNW;
45
        else                    return CARDINAL_DIRECTIONS_ENUM::ERROR;
46
    }
47
48
    static std::string cardinalDirectionsEnumToString(CARDINAL_DIRECTIONS_ENUM e){
49
        switch (e){
50
        case CARDINAL_DIRECTIONS_ENUM::N:
51
            return "N";
52
        case CARDINAL_DIRECTIONS_ENUM::NNE:
53
            return "NNE";
54
        case CARDINAL_DIRECTIONS_ENUM:: NE:
55
            return "NE";
56
        case CARDINAL_DIRECTIONS_ENUM::ENE:
57
            return "ENE";
58
        case CARDINAL_DIRECTIONS_ENUM::E:
59
            return "E";
60
        case CARDINAL_DIRECTIONS_ENUM::ESE:
61
            return "ESE";
62
        case CARDINAL_DIRECTIONS_ENUM::SE:
63
            return "SE";
64
        case CARDINAL_DIRECTIONS_ENUM::SSE:
65
            return "SSE";
66
        case CARDINAL_DIRECTIONS_ENUM::S:
67
            return "S";
68
        case CARDINAL_DIRECTIONS_ENUM::SSW:
69
            return "SSW";
70
        case CARDINAL_DIRECTIONS_ENUM::SW:
71
            return "SW";
72
        case CARDINAL_DIRECTIONS_ENUM::WSW:
73
            return "WSW";
74
        case CARDINAL_DIRECTIONS_ENUM::W:
75
            return "W";
76
        case CARDINAL_DIRECTIONS_ENUM::WNW:
77
            return "WNW";
78
        case CARDINAL_DIRECTIONS_ENUM::NW:
79
            return "NW";
80
        case CARDINAL_DIRECTIONS_ENUM::NNW:
81
            return "NNW";
82
        default:
83
            return "UNKNOWN DIRECTION";
84
        }
85
    }
8
86
    static std::string cardinalDirectionsEnumToHuman(CARDINAL_DIRECTIONS_ENUM e){
0
87
        switch (e){
0
88
        case CARDINAL_DIRECTIONS_ENUM::N:
0
89
            return "północ";
0
90
        case CARDINAL_DIRECTIONS_ENUM::NNE:
0
91
            return "północ - północny wschód";
0
92
        case CARDINAL_DIRECTIONS_ENUM:: NE:
0
93
            return "północny wschód";
6
94
        case CARDINAL_DIRECTIONS_ENUM::ENE:
6
95
            return "wschód - północny wschód";
0
96
        case CARDINAL_DIRECTIONS_ENUM::E:
0
97
            return "wschód";
0
98
        case CARDINAL_DIRECTIONS_ENUM::ESE:
0
99
            return "wschód - południowy wschód";
0
100
        case CARDINAL_DIRECTIONS_ENUM::SE:
0
101
            return "południowy wschód";
0
102
        case CARDINAL_DIRECTIONS_ENUM::SSE:
0
103
            return "południe - południowy wschód";
0
104
        case CARDINAL_DIRECTIONS_ENUM::S:
0
105
            return "południe";
0
106
        case CARDINAL_DIRECTIONS_ENUM::SSW:
0
107
            return "południe - południowy zachów";
0
108
        case CARDINAL_DIRECTIONS_ENUM::SW:
0
109
            return "południowy zachów";
2
110
        case CARDINAL_DIRECTIONS_ENUM::WSW:
2
111
            return "zachód - południowy zachów";
0
112
        case CARDINAL_DIRECTIONS_ENUM::W:
0
113
            return "zachód";
0
114
        case CARDINAL_DIRECTIONS_ENUM::WNW:
0
115
            return "zachód - północny zachód";
0
116
        case CARDINAL_DIRECTIONS_ENUM::NW:
0
117
            return "północny zachód";
0
118
        case CARDINAL_DIRECTIONS_ENUM::NNW:
0
119
            return "północ - północny zachód";
0
120
        default:
0
121
            return "UNKNOWN DIRECTION";
0
122
        }
8
123
    }
124
    struct ALARM_INFO{
125
        ALARM_INFO():
126
            riseAlarm(false),
127
            timestamp(0),
128
            distance(0.0),
129
            bearingENG(CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::ERROR)
130
        {
131
            data << "NULL";
132
        }
133
        ALARM_INFO(const ALARM_INFO &s):
134
            riseAlarm(s.riseAlarm),
135
            data(s.data.str()),
136
            timestamp(s.timestamp),
137
            distance(s.distance),
138
            bearingENG(s.bearingENG)
2
139
        {
2
140
        }
141
        ALARM_INFO& operator = (const ALARM_INFO& s)
142
        {
143
            this->data.str(std::string());
144
            this->riseAlarm = s.riseAlarm;
145
            this->data << s.data.str();
146
            this->timestamp = s.timestamp;
147
            this->distance = s.distance;
148
            this->bearingENG = s.bearingENG;
149
            return *this;
150
        }
151
152
        bool riseAlarm;
153
        std::stringstream data;
154
        unsigned int timestamp; //second
155
        double distance;  //km
156
        CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM bearingENG;
157
    };
158
};
159
160
class LIGHTNING
161
{
162
public:
163
    LIGHTNING();
164
    ~LIGHTNING();
165
    CARDINAL_DIRECTIONS::ALARM_INFO lightningAlert(nlohmann::json jj);
166
    bool checkLightningAlert(CARDINAL_DIRECTIONS::ALARM_INFO* info);
167
private:
168
    bool alarmState = false;
169
    Clock lightningTime;    
170
    double oldDistance = 0.0;
171
};
172
173
#endif // LIGHTNING_H
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/test/../../../libs/useful/useful.h
1
#ifndef Iusefull_H
2
#define Iusefull_H
3
4
#include <iostream>
5
#include <string>
6
#include <vector>
7
#include <ostream>
8
#include <chrono>
9
#include <sstream>
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <iomanip>
13
#ifndef ANDROID
14
#include "json.hpp"
15
#endif
16
17
std::vector<std::string> split_string(const std::string& s, char separator );
18
19
class useful_F_libs {
20
public:
21
    static  void write_to_mkfifo(const std::string &path, const std::string &msg);
22
    static  std::string read_from_mkfifo(const std::string &path);
23
    static size_t  WriteCallback(void *contents, size_t size, size_t nmemb, void *userp);
24
    static std::string find_tag (const std::string &temp);
25
    //////////////////// HTTP req //////////////////////////
26
    static std::string httpPost(const std::string &url, int timeoutSeconds);
27
    static std::string httpPost(const std::string &url);
28
    static void downloadFile(const std::string &url, const std::string &path, int timeoutSeconds);
29
    static std::string replaceAll(std::string str, const std::string& from, const std::string& to);
30
    static std::string removeHtmlTag(std::string &data);
31
    /////////////////////  JSON ////////////////////////////
32
33
#ifndef ANDROID
34
    static nlohmann::json getJson(const std::string &url);
35
#endif
36
};
37
namespace std
38
{
39
40
#ifdef ANDROID
41
template <typename T>
42
int stoi(T s){
43
    return atoi(s.c_str());
44
}
45
#endif
46
47
template <typename T>
48
std::string to_string(T value)
2
49
{
2
50
    std::ostringstream os ;
2
51
    os << value ;
2
52
    return os.str() ;
2
53
}
54
} // namespace std
55
56
template <typename T>
57
std::string to_string_with_precision(const T a_value, const int n = 4)
58
{
59
    std::ostringstream out;
60
    out << std::setprecision(n) << a_value;
61
    return out.str();
62
}
63
64
struct Clock{
65
private:
66
    std::time_t m_time;
67
68
public:
69
    unsigned int m_h = 0;
70
    unsigned int m_min = 0;
71
    Clock () {}
72
    Clock(std::string t){
73
        std::vector<std::string> vt = split_string(t,':');
74
        int h = std::stoi(vt.at(0));
75
        int m = std::stoi(vt.at(1));
76
        set(static_cast <unsigned int>(h),static_cast <unsigned int>(m));
77
    }
78
79
    Clock(unsigned int h, unsigned int m) {
80
        set(h,m);
81
    }
82
    /////////////////////////////////////////////////////////////////////////////////////
83
    void set(unsigned int h, unsigned int m){
84
        if (h<24 && m <60){
85
            this->m_h = h;
86
            this->m_min = m;
87
        }
88
        else {
89
            throw 0;
90
        }
91
    }
92
    /////////////////////////////////////////////////////////////////////////////////////
93
    const std::string getString(){
94
        std::stringstream ret;
95
        if (m_h < 10) {
96
            ret << "0";
97
        }
98
        ret << m_h;
99
        ret << ":";
100
        if (m_min < 10) {
101
            ret << "0";
102
        }
103
        ret << m_min;
104
        return ret.str();
105
    }
106
    /////////////////////////////////////////////////////////////////////////////////////
107
    bool operator == (const Clock & c){
108
        if ((this->m_h == c.m_h) && (this->m_min == c.m_min)){
109
            return true;
110
        }
111
        else{
112
            return false;
113
        }
114
    }
115
    /////////////////////////////////////////////////////////////////////////////////////
116
    bool operator != (const Clock & c){
117
        if ((this->m_h != c.m_h) || (this->m_min != c.m_min)){
118
            return true;
119
        }
120
        else{
121
            return false;
122
        }
123
    }
124
    /////////////////////////////////////////////////////////////////////////////////////
125
    friend std::ostream & operator<< (std::ostream &w ,  Clock &c) {
126
        return w << c.getString();
127
    }
128
    /////////////////////////////////////////////////////////////////////////////////////
129
    bool operator < (const Clock& c){
130
        if (this->m_h < c.m_h){
131
            return true;
132
        }
133
        else{
134
            if (this->m_h == c.m_h && this->m_min < c.m_min){
135
                return true;
136
            }
137
        }
138
        return false;
139
    }
140
    /////////////////////////////////////////////////////////////////////////////////////
141
    bool operator > (const Clock& c){
142
        if (this->m_h > c.m_h){
143
            return true;
144
        }
145
        else{
146
            if (this->m_h == c.m_h && this->m_min > c.m_min){
147
                return true;
148
            }
149
        }
150
        return false;
151
    }
152
    /////////////////////////////////////////////////////////////////////////////////////
153
    bool operator >= (const Clock& c){
154
        if (this->m_h > c.m_h){
155
            return true;
156
        }
157
        else if (this->m_h == c.m_h){
158
159
            if (this->m_min >= c.m_min){
160
                return true;
161
            }
162
        }
163
        return false;
164
    }
165
    /////////////////////////////////////////////////////////////////////////////////////
166
    bool operator <= (const Clock& c){
167
        if (this->m_h < c.m_h){
168
            return true;
169
        }
170
        else if (this->m_h == c.m_h){
171
172
            if (this->m_min <= c.m_min){
173
                return true;
174
            }
175
        }
176
        return false;
177
    }
178
    /////////////////////////////////////////////////////////////////////////////////////
179
    Clock  operator + (const Clock& c){
180
        unsigned int minutes, hours;
181
        minutes = m_min+ c.m_min;
182
        hours = m_h + c.m_h;
183
        if (minutes >59){
184
            minutes =  minutes % 60 ;
185
            hours+=1;
186
        }
187
        if (hours >= 24){
188
            hours-=24;
189
        }
190
        return  Clock(hours, minutes);
191
192
    }
193
    /////////////////////////////////////////////////////////////////////////////////////
194
    Clock&  operator += (const Clock& c){
195
        unsigned int minutes, hours;
196
        minutes = m_min+ c.m_min;
197
        hours = m_h + c.m_h;
198
        if (minutes >59){
199
            minutes =  minutes % 60 ;
200
            hours+=1;
201
        }
202
        if (hours >= 24){
203
            hours-=24;
204
        }
205
        this->m_h = hours;
206
        this->m_min = minutes;
207
        return *this;
208
209
    }
210
    /////////////////////////////////////////////////////////////////////////////////////
211
212
    unsigned int toSeconds(){
213
        return toSeconds(Clock(this->m_h, this->m_min) );
214
    }
215
    /////////////////////////////////////////////////////////////////////////////////////
216
217
    static unsigned int toSeconds(Clock t){
218
        return ((t.m_h*60) + t.m_min)*60;
219
    }
220
    /////////////////////////////////////////////////////////////////////////////////////
221
222
    static Clock fromSeconds(unsigned int sec){
223
        unsigned int h = sec/3600;
224
        unsigned int min = sec%3600;
225
        min = min/60;
226
        return Clock(h,min);
227
    }
228
    /////////////////////////////////////////////////////////////////////////////////////
229
230
    static Clock periodOfTime(Clock start, Clock end)
231
    {
232
        if (end >= start){
233
            return Clock::fromSeconds(end.toSeconds() - start.toSeconds()  );
234
        }
235
        else{
236
            return Clock::fromSeconds(end.toSeconds() + ( Clock::toSeconds(Clock(23,59))+ 60 - start.toSeconds() ) );
237
        }
238
        //return diff;
239
    }
240
    /////////////////////////////////////////////////////////////////////////////////////
241
    static Clock getTime()
242
    {
243
        time_t now = time(0);
244
        tm *ltm = localtime(&now);
245
        return Clock( static_cast <unsigned int>(ltm->tm_hour),static_cast <unsigned int>(ltm->tm_min) );
246
    }
247
    /////////////////////////////////////////////////////////////////////////////////////
248
    void stopwatchStart()
249
    {
250
        m_time = std::time(nullptr);
251
    }
252
    /////////////////////////////////////////////////////////////////////////////////////
253
    unsigned int  stopwatchStopAndGetResult()
254
    {
255
        return static_cast<unsigned int>(std::time(nullptr) - m_time);
256
    }
257
};
258
259
enum class STATE {
260
    OFF,
261
    ON,
262
    UNKNOWN,
263
    PLAY,
264
    PAUSE,
265
    STOP,
266
    ACTIVE,
267
    DEACTIVE,
268
    WORKING,
269
    DEFINE,
270
    UNDEFINE,
271
    LOCK,
272
    UNLOCK,
273
    EMPTY,
274
    FULL,
275
    SEND_OK,
276
    SEND_NOK
277
    //WARNING remember add new state to stateToString() usefull.cpp
278
};
279
280
281
std::string stateToString(STATE s);
282
283
#endif
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/test/../../RADIO_433_eq/radio_433_eq.h
1
#ifndef RADIO_SWITCH_H
2
#define RADIO_SWITCH_H
3
#include <gtest/gtest.h>
4
#include <gmock/gmock.h>
5
#include <map>
6
#include "../iDomStatus/idomstatus.h"
7
#include "../433MHz/RFLink/rflinkhandler.h"
8
9
#include "../433MHz/rc_433mhz.h"
10
#include "json.hpp"
11
12
struct WEATHER_STRUCT{
13
private:
14
    unsigned long int m_counter = 0;
15
protected:
16
    unsigned int m_humidity = 0;
17
    double m_temperature = 0.0;
18
    unsigned int m_barometricPressure = 0;
19
public:
20
    unsigned int getHumidity(){ return m_humidity; }
21
    double getTemperature(){ return m_temperature; }
22
    unsigned int getBarometricPressure(){ return m_barometricPressure; }
23
    std::string getDataString(){
24
        return "data: "+std::to_string(m_counter)+"\n"+"Humidity=" + std::to_string(getHumidity()) +"%\n"+
25
                "temperature= " + to_string_with_precision(getTemperature()) + "c\n"+
26
                "Pressure= " + std::to_string(getBarometricPressure())+ "kPa\n";
27
    }
28
29
    void putData(std::string data){
30
        std::string tempStr;
31
        int t = 0;
32
        ++m_counter;
33
        try{
34
            m_humidity = std::stoi( RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "HUM") );
35
        }
36
        catch (...){  }
37
        try{
38
            tempStr =  RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "TEMP");
39
            std::stringstream ss;
40
            ss << std::hex << tempStr.substr(tempStr.size()-3,tempStr.size());
41
            ss >> t;
42
            m_temperature = t / 10.0;
43
            if(tempStr.at(0) == '8'){
44
                m_temperature *= -1.0;
45
            }
46
        }
47
        catch (...){  }
48
        //std::cout << "DUPA:  "<<data<<" temp=" << m_temperature<< " hum="<<m_humidity<< std::endl;
49
    }
50
};
51
52
enum class RADIO_EQ_TYPE{
53
    SWITCH = 1,
54
    PIR,
55
    GATE,
56
    BUTTON,
57
    WEATHER_S,
58
    NONE
59
};
60
struct RADIO_EQ_CONFIG{
61
    std::string name = "NULL";
62
    std::string ID   = "NULL";
63
    std::string type = "NULL";
64
    std::string onCode  = "NULL";
65
    std::string offCode = "NULL";
66
    std::string on15sec = "NULL";
67
    std::string sunrise = "NULL";
68
    std::string sunset  = "NULL";
69
    std::string lock   = "NULL";
70
    std::string unlock = "NULL";
71
    void set(std::string name,
72
             std::string ID,
73
             std::string type,
74
             std::string onCode,
75
             std::string offCode,
76
             std::string on15sec,
77
             std::string sunrise,
78
             std::string sunset,
79
             std::string lock,
80
             std::string unlock){
81
        this->name = name;
82
        this->ID   = ID;
83
        this->type = type;
84
        this->onCode  = onCode;
85
        this->offCode = offCode;
86
        this->on15sec = on15sec;
87
        this->sunrise = sunrise;
88
        this->sunset  = sunset;
89
        this->lock   = lock;
90
        this->unlock = unlock;
91
    }
92
93
    nlohmann::json getJson(){
94
        nlohmann::json jj;
95
        jj["name"]  = name;
96
        jj["id"]    = ID;
97
        jj["type"]  = type;
98
        jj["ON"]    = onCode;
99
        jj["OFF"]   = offCode;
100
        jj["on15sec"] = on15sec;
101
        jj["sunrise"] = sunrise;
102
        jj["sunset"]  = sunset;
103
        jj["lock"]   = lock;
104
        jj["unlock"] = unlock;
105
        return jj;
106
    }
107
};
108
109
class RADIO_EQ{
110
public:
111
    RADIO_EQ();
112
    virtual ~RADIO_EQ();
113
    virtual STATE getState() = 0;
114
    virtual std::string getName() = 0;
115
    virtual std::string getID() = 0;
116
    virtual RADIO_EQ_TYPE getType();
117
protected:
118
    thread_data *m_my_data;
119
    RADIO_EQ_TYPE m_type;
120
public:
121
    RADIO_EQ_CONFIG m_config;
122
};
123
class RADIO_WEATHER_STATION: public RADIO_EQ
124
{
125
    STATE m_state = STATE::UNDEFINE;
126
127
public:
128
    RADIO_WEATHER_STATION(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
129
    ~RADIO_WEATHER_STATION();
130
    STATE getState();
131
    std::string getName();
132
    std::string getID();
133
    // data
134
    WEATHER_STRUCT data;
135
};
136
class RADIO_BUTTON: public RADIO_EQ
137
{
138
    STATE m_state = STATE::UNDEFINE;
139
140
public:
141
    RADIO_BUTTON(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
142
    ~RADIO_BUTTON();
143
    STATE getState();
144
    void setState(STATE s);
145
    std::string getName();
146
    std::string getID();
147
};
148
149
class RADIO_SWITCH: public RADIO_EQ
150
{
151
    RC_433MHz main433MHz;
152
    STATE m_state = STATE::UNDEFINE;
153
public:
154
    RADIO_SWITCH(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
155
    ~RADIO_SWITCH();
156
    void on();
157
    void off();
158
    void onFor15sec();
159
    void onSunrise();
160
    void onSunset();
161
    void onLockHome();
162
    void onUnlockHome();
163
    STATE getState();
164
    std::string getName();
165
    std::string getID();
166
    void setCode(RADIO_EQ_CONFIG cfg);
167
    STATE m_sunrise = STATE::UNDEFINE;
168
    STATE m_sunset  = STATE::UNDEFINE;
169
};
170
171
class RADIO_EQ_CONTAINER
172
{
173
    std::map <std::string, RADIO_EQ* > m_radioEqMap;
174
    thread_data * my_data;
175
    nlohmann::json m_configJson;
176
public:
177
    RADIO_EQ_CONTAINER(thread_data * my_data);
178
    virtual ~RADIO_EQ_CONTAINER();
179
    void addRadioEq(RADIO_EQ_CONFIG cfg, RADIO_EQ_TYPE type);    
180
    void addRadioEq(RADIO_EQ_CONFIG cfg, const std::string& type);
181
    void deleteRadioEq(const std::string &name);
182
    virtual RADIO_EQ* getEqPointer(std::string name);
183
    std::vector<RADIO_SWITCH*> getSwitchPointerVector();
184
    std::vector<RADIO_BUTTON*> getButtonPointerVector();
185
    std::vector<RADIO_WEATHER_STATION *> getWeather_StationPtrVector();
186
    std::string listAllName();
187
    bool nameExist(const std::string &name);
188
    void loadConfig(const std::string &filePath);
189
    void saveConfig(const std::string &filePath);
190
};
191
192
class RADIO_EQ_CONTAINER_STUB : public RADIO_EQ_CONTAINER
193
{
194
    thread_data * k;
195
public:
2
196
    RADIO_EQ_CONTAINER_STUB(thread_data * k):RADIO_EQ_CONTAINER(k){this->k = k;}
197
2
198
    virtual ~RADIO_EQ_CONTAINER_STUB(){puts("~RADIO_EQ_CONTAINER_STUB()");}
199
    MOCK_METHOD1(getEqPointer, RADIO_EQ*(std::string name));
200
};
201
202
#endif // RADIO_SWITCH_H
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/test/../lightning.h
1
#ifndef LIGHTNING_H
2
#define LIGHTNING_H
3
#include <iostream>
4
5
#include "../../libs/Statistic/statistic.h"
6
#include "../../libs/useful/useful.h"
7
8
#include "idomtools_useful.h"
9
#include "json.hpp"
10
11
class CARDINAL_DIRECTIONS{
12
public:
13
    enum class CARDINAL_DIRECTIONS_ENUM{
14
        /*
15
           N
16
        NNW NNE
17
      NW       NE
18
   WNW		     ENE
19
 W				    E
20
   WSW			 ESE
21
      SW	   SE
22
        SSW	 SSE
23
           S
24
    */
25
26
        N = 1,NNE,NE,ENE,E,ESE,SE,SSE,S,SSW,SW,WSW,W,WNW,NW,NNW,ERROR
27
    };
148
28
    static CARDINAL_DIRECTIONS_ENUM stringToCardinalDirectionsEnum(std::string s){
148
29
        if (s == "N")      return CARDINAL_DIRECTIONS_ENUM::N;
147
30
        else if (s == "NNE")    return CARDINAL_DIRECTIONS_ENUM::NNE;
135
31
        else if (s == "NE")     return CARDINAL_DIRECTIONS_ENUM::NE;
129
32
        else if (s == "ENE")    return CARDINAL_DIRECTIONS_ENUM::ENE;
51
33
        else if (s == "E")      return CARDINAL_DIRECTIONS_ENUM::E;
3
34
        else if (s == "ESE")    return CARDINAL_DIRECTIONS_ENUM::ESE;
3
35
        else if (s == "SE")     return CARDINAL_DIRECTIONS_ENUM::SE;
3
36
        else if (s == "SSE")    return CARDINAL_DIRECTIONS_ENUM::SSE;
3
37
        else if (s == "S")      return CARDINAL_DIRECTIONS_ENUM::S;
3
38
        else if (s == "SSW")    return CARDINAL_DIRECTIONS_ENUM::SSW;
3
39
        else if (s == "SW")     return CARDINAL_DIRECTIONS_ENUM::SW;
3
40
        else if (s == "WSW")    return CARDINAL_DIRECTIONS_ENUM::WSW;
1
41
        else if (s == "W")      return CARDINAL_DIRECTIONS_ENUM::W;
1
42
        else if (s == "WNW")    return CARDINAL_DIRECTIONS_ENUM::WNW;
1
43
        else if (s == "NW")     return CARDINAL_DIRECTIONS_ENUM::NW;
1
44
        else if (s == "NNW")    return CARDINAL_DIRECTIONS_ENUM::NNW;
1
45
        else                    return CARDINAL_DIRECTIONS_ENUM::ERROR;
148
46
    }
47
2
48
    static std::string cardinalDirectionsEnumToString(CARDINAL_DIRECTIONS_ENUM e){
0
49
        switch (e){
0
50
        case CARDINAL_DIRECTIONS_ENUM::N:
0
51
            return "N";
0
52
        case CARDINAL_DIRECTIONS_ENUM::NNE:
0
53
            return "NNE";
0
54
        case CARDINAL_DIRECTIONS_ENUM:: NE:
0
55
            return "NE";
0
56
        case CARDINAL_DIRECTIONS_ENUM::ENE:
0
57
            return "ENE";
0
58
        case CARDINAL_DIRECTIONS_ENUM::E:
0
59
            return "E";
1
60
        case CARDINAL_DIRECTIONS_ENUM::ESE:
1
61
            return "ESE";
0
62
        case CARDINAL_DIRECTIONS_ENUM::SE:
0
63
            return "SE";
0
64
        case CARDINAL_DIRECTIONS_ENUM::SSE:
0
65
            return "SSE";
0
66
        case CARDINAL_DIRECTIONS_ENUM::S:
0
67
            return "S";
0
68
        case CARDINAL_DIRECTIONS_ENUM::SSW:
0
69
            return "SSW";
0
70
        case CARDINAL_DIRECTIONS_ENUM::SW:
0
71
            return "SW";
0
72
        case CARDINAL_DIRECTIONS_ENUM::WSW:
0
73
            return "WSW";
0
74
        case CARDINAL_DIRECTIONS_ENUM::W:
0
75
            return "W";
0
76
        case CARDINAL_DIRECTIONS_ENUM::WNW:
0
77
            return "WNW";
0
78
        case CARDINAL_DIRECTIONS_ENUM::NW:
0
79
            return "NW";
0
80
        case CARDINAL_DIRECTIONS_ENUM::NNW:
0
81
            return "NNW";
1
82
        default:
1
83
            return "UNKNOWN DIRECTION";
0
84
        }
2
85
    }
86
    static std::string cardinalDirectionsEnumToHuman(CARDINAL_DIRECTIONS_ENUM e){
87
        switch (e){
88
        case CARDINAL_DIRECTIONS_ENUM::N:
89
            return "północ";
90
        case CARDINAL_DIRECTIONS_ENUM::NNE:
91
            return "północ - północny wschód";
92
        case CARDINAL_DIRECTIONS_ENUM:: NE:
93
            return "północny wschód";
94
        case CARDINAL_DIRECTIONS_ENUM::ENE:
95
            return "wschód - północny wschód";
96
        case CARDINAL_DIRECTIONS_ENUM::E:
97
            return "wschód";
98
        case CARDINAL_DIRECTIONS_ENUM::ESE:
99
            return "wschód - południowy wschód";
100
        case CARDINAL_DIRECTIONS_ENUM::SE:
101
            return "południowy wschód";
102
        case CARDINAL_DIRECTIONS_ENUM::SSE:
103
            return "południe - południowy wschód";
104
        case CARDINAL_DIRECTIONS_ENUM::S:
105
            return "południe";
106
        case CARDINAL_DIRECTIONS_ENUM::SSW:
107
            return "południe - południowy zachów";
108
        case CARDINAL_DIRECTIONS_ENUM::SW:
109
            return "południowy zachów";
110
        case CARDINAL_DIRECTIONS_ENUM::WSW:
111
            return "zachód - południowy zachów";
112
        case CARDINAL_DIRECTIONS_ENUM::W:
113
            return "zachód";
114
        case CARDINAL_DIRECTIONS_ENUM::WNW:
115
            return "zachód - północny zachód";
116
        case CARDINAL_DIRECTIONS_ENUM::NW:
117
            return "północny zachód";
118
        case CARDINAL_DIRECTIONS_ENUM::NNW:
119
            return "północ - północny zachód";
120
        default:
121
            return "UNKNOWN DIRECTION";
122
        }
123
    }
124
    struct ALARM_INFO{
125
        ALARM_INFO():
126
            riseAlarm(false),
127
            timestamp(0),
128
            distance(0.0),
129
            bearingENG(CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::ERROR)
130
        {
131
            data << "NULL";
132
        }
133
        ALARM_INFO(const ALARM_INFO &s):
134
            riseAlarm(s.riseAlarm),
135
            data(s.data.str()),
136
            timestamp(s.timestamp),
137
            distance(s.distance),
138
            bearingENG(s.bearingENG)
139
        {
140
        }
141
        ALARM_INFO& operator = (const ALARM_INFO& s)
14
142
        {
14
143
            this->data.str(std::string());
14
144
            this->riseAlarm = s.riseAlarm;
14
145
            this->data << s.data.str();
14
146
            this->timestamp = s.timestamp;
14
147
            this->distance = s.distance;
14
148
            this->bearingENG = s.bearingENG;
14
149
            return *this;
14
150
        }
151
152
        bool riseAlarm;
153
        std::stringstream data;
154
        unsigned int timestamp; //second
155
        double distance;  //km
156
        CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM bearingENG;
157
    };
158
};
159
160
class LIGHTNING
161
{
162
public:
163
    LIGHTNING();
164
    ~LIGHTNING();
165
    CARDINAL_DIRECTIONS::ALARM_INFO lightningAlert(nlohmann::json jj);
166
    bool checkLightningAlert(CARDINAL_DIRECTIONS::ALARM_INFO* info);
167
private:
168
    bool alarmState = false;
169
    Clock lightningTime;    
170
    double oldDistance = 0.0;
171
};
172
173
#endif // LIGHTNING_H
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/test/idomTools_BT.cpp
1
#include <gtest/gtest.h>
2
#include <curl/curl.h>
3
4
#include "iDomTools_fixture.h"
5
6
0
7
void useful_F::button_interrupt(){}
3
8
void digitalWrite(int pin, int mode){}
0
9
int digitalRead(int pin){ return 0; }
10
24
11
std::string useful_F::send_to_arduino(thread_data *my_data, const std::string& d){
24
12
    return TEST_DATA::return_send_to_arduino;
24
13
}
53
14
viber_API::viber_API(){}
53
15
void viber_API::setAccessToken(const std::string& accessToken){}
53
16
void viber_API::setURL(const std::string& url){}
55
17
void viber_API::setAvatar (const std::string& avatar){}
18
std::string viber_API::sendViberMSG(const std::string& msg,
19
                                    const std::string& receiver,
20
                                    const std::string& senderName,
21
                                    const std::string& accessToken,
8
22
                                    const std::string& url){
8
23
8
24
    std::cout << "sendViberMSG() "<< msg <<" to: "<< receiver << std::endl;
8
25
    TEST_DATA::return_viber_msg = msg;
8
26
    return"{\"message_status\":\"ok\"}";
8
27
}
28
std::string viber_API::sendViberPicture(const std::string& msg,
29
                                        const std::string& image,
30
                                        const std::string& receiver,
31
                                        const std::string& senderName,
32
                                        const std::string& accessToken ,
15
33
                                        const std::string& url){
15
34
    std::cout << "sendViberPicture() "<< msg <<" to: "<< receiver << std::endl;
15
35
    TEST_DATA::return_viber_msg = msg;
15
36
    return"{\"message_status\":\"ok\"}";
15
37
}
53
38
FACEBOOK_API::FACEBOOK_API(){}
39
std::string FACEBOOK_API::postTxtOnWall(const std::string& msg,
0
40
                                        const std::string& accessToken ){return "";}
41
std::string FACEBOOK_API::postPhotoOnWall(const std::string& url,
42
                                          const std::string& msg ,
1
43
                                          const std::string& accessToken ){return "";}
53
44
void FACEBOOK_API::setAccessToken(const std::string& token){}
45
1
46
void LCD_c::set_lcd_STATE(int i){}
0
47
void LCD_c::printString(bool clear, int col, int row, const std::string& str){
0
48
    std::cout << "LCD_c::printString() "<< str  << std::endl;
0
49
}
50
7
51
std::string useful_F_libs::httpPost(const std::string& url, int timeoutSeconds){
7
52
7
53
    std::cout << "url: "<< url << std::endl;
7
54
    TEST_DATA::return_httpPost_expect = "httpPost";
7
55
    return TEST_DATA::return_httpPost;
7
56
}
4
57
std::string useful_F_libs::httpPost(const std::string& url){
4
58
CURL *curl;
4
59
CURLcode res;
4
60
std::string readBuffer;
4
61
curl = curl_easy_init();
4
62
4
63
if(curl) {
4
64
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
4
65
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
4
66
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, useful_F_libs::WriteCallback);
4
67
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
4
68
    res = curl_easy_perform(curl);
4
69
    /* Check for errors */
4
70
    if(res != CURLE_OK)
0
71
        fprintf(stderr, "curl_easy_perform() failed: %s\n",
0
72
                curl_easy_strerror(res));
4
73
4
74
    /* always cleanup */
4
75
    curl_easy_cleanup(curl);
4
76
}
4
77
curl_global_cleanup();
4
78
4
79
return readBuffer;
4
80
}
81
82
TEST_F(iDomTOOLS_ClassTest, smog)
1
83
{
1
84
    std::string smog = test_idomTOOLS->getSmog();
1
85
    puts(smog.c_str());
1
86
    puts(" smog");
1
87
    ASSERT_GE(smog.size(),1);
1
88
1
89
    unsigned int smog_int = std::stoi(smog);
1
90
    ASSERT_GT(smog_int,1);
1
91
    ASSERT_LT(smog_int,1000);
1
92
}
93
94
TEST_F(iDomTOOLS_ClassTest, hasTemperatureChange)
1
95
{
1
96
    std::cout << "##################################### 0" <<std::endl;
1
97
1
98
    TEST_DATA::return_send_to_arduino = "20.0:-1.0;";
1
99
    test_idomTOOLS->send_temperature_thingSpeak();
1
100
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::Under);
1
101
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::NoChanges);
1
102
    std::cout << "##################################### 1" <<std::endl;
1
103
1
104
    TEST_DATA::return_send_to_arduino = "25.4:0.0;";
1
105
    test_idomTOOLS->send_temperature_thingSpeak();
1
106
1
107
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::NoChanges);
1
108
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::Over);
1
109
1
110
    std::cout << "##################################### 2" <<std::endl;
1
111
1
112
    TEST_DATA::return_send_to_arduino = "21.0:1.0;";
1
113
    test_idomTOOLS->send_temperature_thingSpeak();
1
114
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::Over);
1
115
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::Under);
1
116
1
117
    std::cout << "##################################### 3" <<std::endl;
1
118
    TEST_DATA::return_send_to_arduino = "21.0:5.0;";
1
119
    test_idomTOOLS->send_temperature_thingSpeak();
1
120
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::NoChanges);
1
121
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::NoChanges);
1
122
1
123
    std::cout << "##################################### 4" <<std::endl;
1
124
    TEST_DATA::return_send_to_arduino = "21.0:4.0;";
1
125
    test_idomTOOLS->send_temperature_thingSpeak();
1
126
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::NoChanges);
1
127
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::NoChanges);
1
128
    std::cout << "##################################### 5" <<std::endl;
1
129
1
130
    TEST_DATA::return_send_to_arduino = "31.9:11.11;";
1
131
    test_idomTOOLS->send_temperature_thingSpeak();
1
132
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::NoChanges);
1
133
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::Over);
1
134
    std::cout << "##################################### 6" <<std::endl;
1
135
}
136
137
TEST_F(iDomTOOLS_ClassTest, weatherAlert)
1
138
{
1
139
    std::string test_data_from_www = "    <div style=\"margin:0;padding:0;width:350px;font:0.8em Lucida,Arial,sans-seri                                                                  f;background:#FFC\">\
1
140
            <p style=\"margin:1px;padding:1px;text-align:center;background:#FF9;borde \                                                                 r:1px dotted\"><b><a href=\"http://burze.dzis.net?page=wyszukiwarka&amp;miejscowos\                                                                  c=krakow\" target=\"_blank\" style=\"color:#00E\">krakow</a></b>\
1
141
            <i>(50°03'N 19°57'E)</i>\
1
142
            </p>\
1
143
            <dl style=\"margin:1px 1px 0 1px;padding:0;cl                                                                  ear:both;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:\                                                                  center\">Zarejestrowano 54 wyładowania atmosferyczne w promieniu 300km . Najbliższe 79.76km na zachód.\
1
144
            </dl>\
1
145
            \
1
146
            <dl style=\"margin:1px 1px 0 1px;padding:0;cl                                                                  ear:both;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:  \                                                                center\">Mróz, brak ostrzeżeń</dl>\
1
147
            \
1
148
            <dl style=\"margin:1px 1px 0 1px;padding:0;clear:both                                                                  ;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:center\">  \                                                                Upał, brak ostrzeżeń</dl>\
1
149
            \
1
150
            <dl style=\"margin:1px 1px 0 1px;padding:0;clear:both                                                                  ;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:center\">  \                                                                Wiatr, brak ostrzeżeń</dl>\
1
151
            \
1
152
            <dl style=\"margin:1px 1px 0 1px;padding:0;clear:both                                                                  ;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:center\">  \                                                                Opady, brak ostrzeżeń</dl>\
1
153
            \
1
154
            <dl style=\"margin:1px 1px 0 1px;padding:0;clear:both                                                                  ;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:center\">  \                                                                Burze, brak ostrzeżeń</dl>\
1
155
            \
1
156
            <dl style=\"margin:1px 1px 0 1px;padding:0;clear:both                                                                  ;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:center\">  \                                                                Trąby powietrzne, brak ostrzeżeń</dl>\
1
157
            </div>";
1
158
1
159
1
160
    std::vector<WEATHER_ALER> test_WA;
1
161
    test_WA =  test_idomTOOLS->getAlert(test_data_from_www);
3
162
    EXPECT_EQ(1,test_WA.size()) << "ZŁY ROZMIAR VEKTORA WA";
1
163
}
164
1
165
TEST_F(iDomTOOLS_ClassTest, send_temperature_thingSpeak){
1
166
1
167
    TEST_DATA::return_httpPost_expect = "NULL";
1
168
1
169
    EXPECT_STREQ(TEST_DATA::return_httpPost_expect.c_str(),"NULL");
1
170
    test_idomTOOLS->send_temperature_thingSpeak();
1
171
    EXPECT_STREQ(TEST_DATA::return_httpPost_expect.c_str(),"httpPost");
1
172
}
173
174
TEST_F(iDomTOOLS_ClassTest, checkAlarm)
1
175
{
1
176
    unsigned int fromVol = 48;
1
177
    unsigned int  toVol = 57;
1
178
1
179
    ///////////////////////////////////// to save
1
180
    test_status.setObjectState("house",STATE::UNLOCK);
1
181
    test_status.setObjectState("music", STATE::PLAY);
1
182
    test_status.setObjectState("speakers", STATE::ON);
1
183
    test_my_data.idom_all_state.houseState = STATE::LOCK;
1
184
1
185
    test_status.setObjectState("listwa",STATE::ON);
1
186
1
187
    test_alarmTime.time = Clock::getTime();
1
188
    test_alarmTime.state = STATE::ACTIVE;
1
189
    test_alarmTime.toVolume = 58;
1
190
    test_alarmTime.fromVolume = 48;
1
191
    test_status.setObjectState("alarm", test_alarmTime.state);
1
192
    test_my_data.alarmTime = test_alarmTime;
1
193
    useful_F::myStaticData = &test_my_data;
1
194
1
195
    //////////////////////////////////////////////////////////////
1
196
1
197
    MPD_info test_ptr_MPD;
1
198
    test_ptr_MPD.volume = 3;
1
199
    test_my_data.ptr_MPD_info = &test_ptr_MPD;
1
200
    RADIO_EQ_CONFIG cfg;
1
201
    cfg.name = "listwa";
1
202
    cfg.ID = "209888";
1
203
    RADIO_EQ* test_RS = new RADIO_SWITCH(&test_my_data,cfg,RADIO_EQ_TYPE::SWITCH);
1
204
1
205
    RADIO_EQ_CONTAINER_STUB stub_rec(&test_my_data);
1
206
    test_my_data.main_REC = (&stub_rec);
1
207
    test_my_data.alarmTime.time = Clock::getTime();
1
208
    test_my_data.alarmTime.state = STATE::ACTIVE;
1
209
1
210
    EXPECT_EQ(test_my_data.alarmTime.state, STATE::ACTIVE);
1
211
10
212
    for(unsigned int i = fromVol; i<toVol; ++i)
9
213
    {
9
214
        test_idomTOOLS->checkAlarm();
9
215
27
216
        EXPECT_EQ(test_my_data.alarmTime.state, STATE::WORKING)<< "zły stan w for " << i<< " "<< toVol;
27
217
        EXPECT_EQ(test_my_data.ptr_MPD_info->volume, i+1) << "zły poziom glosnosci w for";
9
218
    }
1
219
    EXPECT_CALL(stub_rec, getEqPointer("ALARM")).WillRepeatedly(testing::Return(test_RS));
1
220
    test_idomTOOLS->checkAlarm();
1
221
3
222
    EXPECT_EQ(test_my_data.alarmTime.state, STATE::DEACTIVE) << "nie jest STATE::DEACTIVE";
3
223
    EXPECT_EQ(test_my_data.ptr_MPD_info->volume, toVol)<< "nie inkrementowane?";
1
224
1
225
    delete test_RS;
1
226
}
227
228
TEST_F(iDomTOOLS_ClassTest, homeLockPlayStopMusic)
1
229
{
1
230
    ///////////////////////////////////// to save
1
231
    test_status.setObjectState("house",STATE::UNDEFINE);
1
232
    test_status.setObjectState("music", STATE::PLAY);
1
233
    test_status.setObjectState("speakers", STATE::ON);
1
234
    test_my_data.idom_all_state.houseState = STATE::LOCK;
1
235
1
236
    test_status.setObjectState("listwa",STATE::ON);
1
237
1
238
    test_alarmTime.time = Clock::getTime();
1
239
    test_alarmTime.state = STATE::ACTIVE;
1
240
    test_status.setObjectState("alarm", test_alarmTime.state);
1
241
1
242
    blockQueue test_q;
1
243
    test_q._clearAll();
1
244
    EXPECT_EQ(test_q._size(),0);
1
245
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNDEFINE);
1
246
    test_idomTOOLS->lockHome();
1
247
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
1
248
    test_idomTOOLS->MPD_play(&test_my_data);
1
249
    EXPECT_EQ(test_q._size(),0);
1
250
    test_idomTOOLS->unlockHome();
1
251
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
1
252
    test_idomTOOLS->MPD_play(&test_my_data);
1
253
    EXPECT_EQ(test_q._size(),1);
1
254
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
1
255
    EXPECT_EQ(test_q._size(),0);
1
256
    test_idomTOOLS->lockHome();
1
257
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
1
258
    test_idomTOOLS->MPD_stop();
1
259
    EXPECT_EQ(test_q._size(),1);
1
260
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP);
1
261
    EXPECT_EQ(test_q._size(),0);
1
262
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
1
263
    std::string returnedString = test_status.getAllObjectsStateString();
1
264
    EXPECT_THAT(returnedString, testing::HasSubstr("LOCK"));
1
265
}
266
267
TEST_F(iDomTOOLS_ClassTest, buttonPressed)
1
268
{
1
269
    std::string button433MHz_id = "01e7be";
1
270
    std::string pressedButtonName = test_idomTOOLS->buttonPressed(button433MHz_id);
1
271
    EXPECT_EQ(1, test_my_data.main_REC->getButtonPointerVector().size());
1
272
    EXPECT_STREQ(std::to_string(button433MHz_id).c_str(),
1
273
                 test_my_data.main_REC->getButtonPointerVector().at(0)->getID().c_str());
1
274
    EXPECT_STREQ(pressedButtonName.c_str(), "locker");
1
275
1
276
    EXPECT_THROW(test_idomTOOLS->buttonPressed(button433MHz_id+"a"),
1
277
                 std::string);
1
278
}
279
280
TEST_F(iDomTOOLS_ClassTest, button433MHzPressedAction_lockerUnlock)
1
281
{
1
282
    blockQueue test_q;
1
283
    test_q._clearAll();
1
284
1
285
    test_idomTOOLS->unlockHome();
1
286
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
1
287
3
288
    for(auto i : {1,2,3}){
3
289
        test_idomTOOLS->button433MHzPressedAction("locker");
3
290
    }
1
291
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
1
292
1
293
    EXPECT_EQ(test_q._size(),1);
1
294
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP);
1
295
1
296
}
297
298
TEST_F(iDomTOOLS_ClassTest, button433MHzPressedAction_lockerLock)
1
299
{
1
300
    blockQueue test_q;
1
301
    test_q._clearAll();
1
302
3
303
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNDEFINE) << "nie jest UNDEFINED";
1
304
1
305
    test_idomTOOLS->button433MHzPressedAction("locker");
3
306
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK)<< "nie jest UNLOCK";
1
307
1
308
    EXPECT_EQ(test_q._size(),1);
1
309
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
1
310
    EXPECT_EQ(test_q._size(),0);
1
311
}
312
313
TEST_F(iDomTOOLS_ClassTest, testCPU_Load)
1
314
{
1
315
    std::cout <<"TEST LOAD" << std::endl;
1
316
    std::cout << test_idomTOOLS->getSystemInfo() << std::endl;
1
317
}
318
TEST_F(iDomTOOLS_ClassTest, stringToCardinalDirectionsEnum)
1
319
{
1
320
    EXPECT_EQ(CARDINAL_DIRECTIONS::stringToCardinalDirectionsEnum("NWWA"),
1
321
              CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::ERROR);
1
322
    EXPECT_EQ(CARDINAL_DIRECTIONS::stringToCardinalDirectionsEnum("N"),
1
323
              CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::N);
1
324
}
325
326
TEST_F(iDomTOOLS_ClassTest, cardinalDirectionsEnumToString)
1
327
{
1
328
    EXPECT_STREQ( CARDINAL_DIRECTIONS::cardinalDirectionsEnumToString(CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::ERROR).c_str(),
1
329
              "UNKNOWN DIRECTION");
1
330
    EXPECT_STREQ( CARDINAL_DIRECTIONS::cardinalDirectionsEnumToString(CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::ESE).c_str(),
1
331
              "ESE");
1
332
}
333
334
TEST_F(iDomTOOLS_ClassTest, saveState)
1
335
{
1
336
    test_status.setObjectState("house",STATE::UNLOCK);
1
337
//////////////////// mpd
1
338
    test_status.setObjectState("music", STATE::PLAY);
1
339
    test_status.setObjectState("speakers", STATE::ON);
1
340
    test_my_data.idom_all_state.houseState = STATE::LOCK;
1
341
1
342
    test_status.setObjectState("listwa",STATE::ON);
1
343
    test_alarmTime.time = Clock::getTime();
1
344
    test_alarmTime.state = STATE::ACTIVE;
1
345
    test_alarmTime.fromVolume = 0;
1
346
    test_alarmTime.toVolume = 100;
1
347
    test_alarmTime.radioID = 44;
1
348
    test_my_data.alarmTime = test_alarmTime;
1
349
    test_status.setObjectState("alarm", test_alarmTime.state);
1
350
1
351
    test_idomTOOLS->saveState_iDom();
1
352
1
353
    nlohmann::json testJson;
1
354
    std::ifstream i(test_server_set.saveFilePath);
1
355
    i >> testJson;
1
356
    EXPECT_STREQ(test_status.getObjectStateString("music").c_str(),
1
357
                 testJson.at("MPD").at("music").get<std::string>().c_str() );
1
358
    EXPECT_STREQ((test_status.getObjectStateString("alarm")).c_str(),
1
359
                 testJson.at("ALARM").at("alarm").get<std::string>().c_str() );
1
360
    EXPECT_EQ(test_alarmTime.radioID,
1
361
                 testJson.at("ALARM").at("radioID").get<int>() );
1
362
    EXPECT_EQ(test_alarmTime.fromVolume,
1
363
                 testJson.at("ALARM").at("fromVolume").get<int>() );
1
364
    EXPECT_EQ(test_alarmTime.toVolume,
1
365
                     testJson.at("ALARM").at("toVolume").get<int>() );
1
366
}
367
368
TEST_F(iDomTOOLS_ClassTest, readState)
1
369
{
1
370
    test_idomTOOLS->readState_iDom();
1
371
    EXPECT_EQ(test_my_data.alarmTime.state,STATE::ACTIVE);
1
372
}
373
374
TEST_F(iDomTOOLS_ClassTest, getLightningStruct)
1
375
{
1
376
    LIGHTNING test_lightning;
1
377
    test_struct = test_lightning.lightningAlert(test_Json.jj_lightning);
1
378
1
379
    test_idomTOOLS->setLightningStruct(test_struct);
1
380
1
381
    bool test_result = test_lightning.checkLightningAlert(&test_struct);
1
382
    EXPECT_TRUE(test_result);
1
383
1
384
    auto test_alert_info = test_idomTOOLS->getLightningStruct();
1
385
    EXPECT_EQ(test_alert_info.timestamp,210);
1
386
}
387
TEST_F(iDomTOOLS_ClassTest, checkLightning)
1
388
{
1
389
    test_my_data.server_settings->lightningApiURL = "http://cyniu88.no-ip.pl/test/json/lightning.json";
1
390
    test_idomTOOLS->checkLightning();
1
391
    auto test_alert_info = test_idomTOOLS->getLightningStruct();
1
392
    EXPECT_EQ(test_alert_info.timestamp,210);
1
393
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/iDomTools/test/lightning_BT.cpp
1
#include <gtest/gtest.h>
2
3
#include "test_data.h"
4
#include "testJSON.h"
5
#include "../idomtools.h"
6
7
class lightning_Class : public ::testing::Test
8
{
9
protected:
10
    TEST_JSON test_Json;
11
    LIGHTNING test_lightning;
12
    CARDINAL_DIRECTIONS::ALARM_INFO test_struct;
13
    virtual void SetUp() final
5
14
    {
5
15
        std::cout << "konfiguracja przed testem lightning_Class " <<std::endl;
5
16
    }
17
18
    virtual void TearDown() final
5
19
    {
5
20
        std::cout << "czyszczenie po tescie lightning_Class " <<std::endl;
5
21
    }
22
};
23
24
TEST_F(lightning_Class, lightningAlertOFF)
1
25
{
1
26
    test_struct = test_lightning.lightningAlert(test_Json.jj_noLightning);
1
27
    std::cout <<std::endl << test_struct.data.str();
3
28
    EXPECT_FALSE(test_struct.riseAlarm) << "BRAK ALARMU";
1
29
}
30
31
TEST_F(lightning_Class, lightningAlertON)
1
32
{
1
33
    test_struct = test_lightning.lightningAlert(test_Json.jj_lightning);
1
34
    std::cout <<std::endl << test_struct.data.str();
3
35
    EXPECT_TRUE(test_struct.riseAlarm) << "BRAK ALARMU";
1
36
}
37
38
TEST_F(lightning_Class, checkLightningAlert)
1
39
{
1
40
1
41
    nlohmann::json test_Json2 = useful_F_libs::getJson("http://cyniu88.no-ip.pl/test/json/on_lightning.json");
1
42
    test_struct = test_lightning.lightningAlert(test_Json.jj_noLightning);
1
43
1
44
    bool test_result = test_lightning.checkLightningAlert(&test_struct);
1
45
3
46
    EXPECT_FALSE(test_result) << "BRAK ALARMU 1";
1
47
    test_struct = test_lightning.lightningAlert(test_Json2);
1
48
    test_result = test_lightning.checkLightningAlert(&test_struct);
3
49
    EXPECT_TRUE(test_result) << "BRAK ALARMU 2";
1
50
    test_result = test_lightning.checkLightningAlert(&test_struct);
3
51
    EXPECT_FALSE(test_result) << "BRAK ALARMU 3";
1
52
    test_struct.riseAlarm = false;
1
53
    test_result = test_lightning.checkLightningAlert(&test_struct);
3
54
    EXPECT_FALSE(test_result) << "BRAK ALARMU 4";
1
55
    test_struct.riseAlarm = false;
1
56
    test_result = test_lightning.checkLightningAlert(&test_struct);
3
57
    EXPECT_FALSE(test_result) << "BRAK ALARMU 5";
1
58
}
59
60
TEST_F(lightning_Class, checkLightningAlert_stormCloser)
1
61
{
1
62
    nlohmann::json test_Json2 = useful_F_libs::getJson("http://cyniu88.no-ip.pl/test/json/on_lightning.json");
1
63
1
64
    test_struct = test_lightning.lightningAlert(test_Json.jj_noLightning);
1
65
    bool test_result = test_lightning.checkLightningAlert(&test_struct);
3
66
    EXPECT_FALSE(test_result) << "BRAK ALARMU 1";
1
67
1
68
    test_struct = test_lightning.lightningAlert(test_Json2);
1
69
    test_result = test_lightning.checkLightningAlert(&test_struct);
3
70
    EXPECT_TRUE(test_result) << "BRAK ALARMU 2";
1
71
1
72
    test_result = test_lightning.checkLightningAlert(&test_struct);
3
73
    EXPECT_FALSE(test_result) << "BRAK ALARMU 3";
1
74
1
75
    test_struct = test_lightning.lightningAlert(test_Json.jj_lightning_lt15km);
1
76
    test_result = test_lightning.checkLightningAlert(&test_struct);
3
77
    EXPECT_TRUE(test_result) << "BRAK ALARMU 4";
1
78
1
79
    test_struct = test_lightning.lightningAlert(test_Json.jj_lightning_lt15km);
1
80
    test_result = test_lightning.checkLightningAlert(&test_struct);
3
81
    EXPECT_FALSE(test_result) << "BRAK ALARMU 5";
1
82
1
83
    test_struct = test_lightning.lightningAlert(test_Json.jj_noLightning);
1
84
    test_result = test_lightning.checkLightningAlert(&test_struct);
3
85
    EXPECT_FALSE(test_result) << "BRAK ALARMU 6";
1
86
1
87
    test_struct = test_lightning.lightningAlert(test_Json.jj_lightning_lt15km);
1
88
    test_result = test_lightning.checkLightningAlert(&test_struct);
3
89
    EXPECT_TRUE(test_result) << "BRAK ALARMU 7";
1
90
}
91
92
TEST_F(lightning_Class, oneLightning)
1
93
{
1
94
    test_struct = test_lightning.lightningAlert(test_Json.jj_oneLightning);
1
95
    bool test_result = test_lightning.checkLightningAlert(&test_struct);
1
96
    EXPECT_FALSE(test_result);
1
97
}
/home/cyniu/GIT/malina/iDom_server_OOP/src/thread_functions/TEST/../rs232_thread.h
1
#ifndef RS232_THREAD_H
2
#define RS232_THREAD_H
3
4
#include "../c_connection/c_connection.h"
5
#include "../TASKER/tasker.h"
6
#include "../SerialPi/serialpi.h"
7
8
9
//////////// watek wysylajacy/obdbierajacy dane z portu RS232 ////////
4
10
void Send_Recieve_rs232_thread (thread_data_rs232 *data_rs232){
4
11
4
12
    SerialPi serial_ardu(data_rs232->portRS232);
4
13
    serial_ardu.begin( std::stoi( data_rs232->BaudRate));
4
14
#ifndef BT_TEST
15
    log_file_mutex.mutex_lock();
16
    log_file_cout << INFO <<"otwarcie portu RS232 " <<  data_rs232->portRS232 << "  " <<data_rs232->BaudRate<<std::endl;
17
    log_file_mutex.mutex_unlock();
18
#endif
4
19
    SerialPi serial_ardu_clock(data_rs232->portRS232_clock);
4
20
    serial_ardu_clock.begin( std::stoi( data_rs232->BaudRate));
4
21
#ifndef BT_TEST
22
    log_file_mutex.mutex_lock();
23
    log_file_cout << INFO <<"otwarcie portu RS232_clock " <<  data_rs232->portRS232_clock <<" "<< data_rs232->BaudRate <<std::endl;
24
    log_file_mutex.mutex_unlock();
25
#endif
4
26
    /////////////////////////////////////////////////// RESET ARDUINO AFTER RESTART ////////////////////////////////
4
27
    puts("restart arduino\n");
4
28
    //C_connection::mutex_who.lock();
4
29
    {
4
30
        std::lock_guard<std::mutex> lockWho(useful_F::mutex_who);
4
31
        buffer = "reset:00;";
4
32
        serial_ardu.print(buffer.c_str());
4
33
    }
4
34
    //C_connection::mutex_who.unlock();
4
35
    puts("test testo po lock");
4
36
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4
37
    while(useful_F::go_while)
4
38
    {
4
39
        puts("test");
4
40
        std::this_thread::sleep_for( std::chrono::milliseconds(50));
4
41
        //puts("test testo po lock");
4
42
        { //mutex who
4
43
            std::lock_guard<std::mutex> lockWho(useful_F::mutex_who);
4
44
4
45
            if(data_rs232->pointer.ptr_who[0] == iDomConst::RS232)
1
46
            {
1
47
                std::lock_guard<std::mutex> lockBuf(useful_F::mutex_buf);
1
48
                data_rs232->pointer.ptr_who[0] = data_rs232->pointer.ptr_who[1];
1
49
                data_rs232->pointer.ptr_who[1] = iDomConst::RS232;
1
50
                serial_ardu.print(buffer.c_str());
1
51
1
52
                buffer.erase();
1
53
3
54
                while(useful_F::go_while){
3
55
                    if(serial_ardu.available()>0){
3
56
                        buffer += serial_ardu.read();
3
57
                    }
3
58
                    if(buffer[buffer.size()-1] == ';')
1
59
                    {
1
60
                        buffer.erase(buffer.end()-1);
1
61
                        break;
1
62
                    }
3
63
                }
1
64
#ifdef BT_TEST
1
65
                useful_F::go_while = false;
1
66
                return;
1
67
#endif
1
68
            }
3
69
            else if(data_rs232->pointer.ptr_who[0] == iDomConst::CLOCK)
2
70
            {
2
71
                std::lock_guard<std::mutex> lockBuf(useful_F::mutex_buf);
2
72
                data_rs232->pointer.ptr_who[0] = data_rs232->pointer.ptr_who[1];
2
73
                data_rs232->pointer.ptr_who[1] = iDomConst::CLOCK;
2
74
                serial_ardu_clock.print(buffer.c_str());
2
75
2
76
                buffer.erase();
2
77
2
78
                while(useful_F::go_while){
2
79
                    if(serial_ardu_clock.available()>0)
1
80
                    {
1
81
                        buffer += serial_ardu_clock.read();
1
82
                        buffer += serial_ardu_clock.read();
1
83
                        serial_ardu_clock.flush();
1
84
                        break;
1
85
                    }
2
86
                    else
1
87
                    {
1
88
                        puts("w buforze serial_ardu_clock nie ma avaiable ");
1
89
1
90
                        useful_F::myStaticData->myEventHandler.run("RS232")
1
91
                                ->addEvent("w buforze serial_ardu_clock nie ma avaiable ");
1
92
                        break;
1
93
                    }
2
94
                }
2
95
#ifdef BT_TEST
2
96
                useful_F::go_while = false;
2
97
                return;
2
98
#endif
2
99
            }
1
100
            else if(data_rs232->pointer.ptr_who[0] == iDomConst::FREE)
1
101
            {
1
102
                std::string bufor = "";
1
103
                if(serial_ardu.available()>0) {
1
104
5
105
                    while (useful_F::go_while){
5
106
                        // std::cout << "serial_ardu.available(): "<<serial_ardu.available()<<std::endl;
5
107
                        if(serial_ardu.available()>0){
5
108
                            char t = serial_ardu.read();
5
109
                            // std::cout << "t: "<<t<<std::endl;
5
110
                            if(t == ';'){
1
111
                                serial_ardu.flush();
1
112
                                break;
1
113
                            }
4
114
                            else{
4
115
                                printf("%c",t);
4
116
                                bufor.push_back(t);
4
117
                            }
5
118
                        }
5
119
                    }
1
120
                    useful_F::myStaticData->myEventHandler.run("RS232")->addEvent(bufor);
1
121
1
122
                }
1
123
#ifdef BT_TEST
1
124
                useful_F::go_while = false;
1
125
                return;
1
126
#endif
1
127
            }
4
128
4
129
        }
4
130
    }
4
131
}
132
#endif // RS232_THREAD_H
/home/cyniu/GIT/malina/iDom_server_OOP/src/thread_functions/TEST/rs232_thread_BT.cpp
1
#include <gtest/gtest.h>
2
#include "../../iDom_server_OOP.h"
3
#include "../rs232_thread.h"
4
#include "test_data.h"
5
#include "../../../iDom_server_OOP/src/iDomTools/test/iDomTools_fixture.h"
6
7
std::mutex useful_F::mutex_buf;
8
std::mutex useful_F::mutex_who;
9
10
std::string buffer;
11
12
class rs232_thread_fixture : public iDomTOOLS_ClassTest
13
{
14
15
};
16
5
17
void SerialPi_set_recv_msg(const std::string& m){
5
18
    TEST_DATA::serial_b = m;
5
19
}
20
26
21
SerialPi::SerialPi(const std::string& a):m_serial_port(10){
26
22
    std::cout << "SerialPi() addres: " << a << std::endl;
26
23
}
26
24
SerialPi::~SerialPi(){
26
25
    std::cout << "~SerialPi()" << std::endl;
26
26
}
27
8
28
void SerialPi::begin(int serialSpeed){
8
29
    std::cout << "SerialPi::int() serialSpeed: " << serialSpeed << std::endl;
8
30
}
31
9
32
void SerialPi::print(const std::string& msg){
9
33
    std::cout << "SerialPi::print() msg: " << msg << std::endl;
9
34
    //TEST_DATA::serial_b = msg;
9
35
}
2
36
void SerialPi::flush(){
2
37
    std::cout << "SerialPi::flush()" << std::endl;
2
38
    TEST_DATA::serial_b.clear();
2
39
}
40
13
41
int SerialPi::available(){
13
42
    std::cout << "SerialPi::available() " << TEST_DATA::serial_b.size() << std::endl;
13
43
    return TEST_DATA::serial_b.size();
13
44
}
45
31
46
char SerialPi::read(){
31
47
    std::cout << "SerialPi::read()"<< std::endl;
31
48
    char r = TEST_DATA::serial_b.at(0);
31
49
    TEST_DATA::serial_b.erase(0,1);
31
50
    std::cout << "SerialPi::read() "<<r<< std::endl;
31
51
    return r;
31
52
}
53
0
54
TASKER::TASKER(thread_data *my_data){
0
55
    this->my_data = std::nullptr_t();
0
56
    std::cout << "TASKER::TASKER()"<< std::endl;
0
57
}
58
59
bool useful_F::go_while = true;
60
61
TEST_F(rs232_thread_fixture, send_Recieve_rs232_thread_fixture_clock)
1
62
{
1
63
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 0);
1
64
    thread_data_rs232 test_data_rs232;
1
65
    test_data_rs232.BaudRate = "9600";
1
66
    test_data_rs232.portRS232 = "test_port";
1
67
    test_data_rs232.portRS232_clock = "test_port_clock";
1
68
    unsigned int test_who[2] = {iDomConst::CLOCK, iDomConst::FREE};
1
69
    EXPECT_EQ(test_who[1], iDomConst::FREE);
1
70
    test_data_rs232.pointer.ptr_who = test_who;
1
71
1
72
    SerialPi_set_recv_msg("OK");
1
73
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"OK");
1
74
    Send_Recieve_rs232_thread(&test_data_rs232);
1
75
1
76
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"");
1
77
    EXPECT_EQ(test_data_rs232.pointer.ptr_who[1], iDomConst::CLOCK);
1
78
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 0);
1
79
}
80
81
TEST_F(rs232_thread_fixture, send_Recieve_rs232_thread_clock_empty_answer)
1
82
{
1
83
    useful_F::go_while = true;
1
84
    thread_data_rs232 test_data_rs232;
1
85
    test_data_rs232.BaudRate = "9600";
1
86
    test_data_rs232.portRS232 = "test_port";
1
87
    test_data_rs232.portRS232_clock = "test_port_clock";
1
88
    unsigned int test_who[2] = {iDomConst::CLOCK, iDomConst::FREE};
1
89
    EXPECT_EQ(test_who[1], iDomConst::FREE);
1
90
    test_data_rs232.pointer.ptr_who = test_who;
1
91
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 0);
1
92
    SerialPi_set_recv_msg("");
1
93
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"");
1
94
    Send_Recieve_rs232_thread(&test_data_rs232);
1
95
1
96
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"");
1
97
    EXPECT_EQ(test_data_rs232.pointer.ptr_who[1], iDomConst::CLOCK);
1
98
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 1);
1
99
}
100
101
TEST_F(rs232_thread_fixture, send_Recieve_rs232_thread_RS232)
1
102
{
1
103
    useful_F::go_while = true;
1
104
    thread_data_rs232 test_data_rs232;
1
105
    test_data_rs232.BaudRate = "9600";
1
106
    test_data_rs232.portRS232 = "test_port";
1
107
    test_data_rs232.portRS232_clock = "test_port_clock";
1
108
    unsigned int test_who[2] = {iDomConst::RS232, iDomConst::FREE};
1
109
    test_data_rs232.pointer.ptr_who = test_who;
1
110
1
111
    test_data_rs232.pointer.ptr_who[0] = iDomConst::RS232;
1
112
    EXPECT_EQ(test_who[0], iDomConst::RS232);
1
113
    SerialPi_set_recv_msg("OK;");
1
114
    Send_Recieve_rs232_thread(&test_data_rs232);
1
115
1
116
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"");
1
117
    EXPECT_EQ(test_who[1], iDomConst::RS232);
1
118
}
119
120
TEST_F(rs232_thread_fixture, send_Recieve_rs232_thread_FREE)
1
121
{
1
122
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 0);
1
123
    useful_F::go_while = true;
1
124
    thread_data_rs232 test_data_rs232;
1
125
    test_data_rs232.BaudRate = "9600";
1
126
    test_data_rs232.portRS232 = "test_port";
1
127
    test_data_rs232.portRS232_clock = "test_port_clock";
1
128
    unsigned int test_who[2] = {iDomConst::FREE, iDomConst::FREE};
1
129
    test_data_rs232.pointer.ptr_who = test_who;
1
130
1
131
    test_data_rs232.pointer.ptr_who[0] = iDomConst::FREE;
1
132
    EXPECT_EQ(test_who[0], iDomConst::FREE);
1
133
    SerialPi_set_recv_msg("TEST;");
1
134
    Send_Recieve_rs232_thread(&test_data_rs232);
1
135
1
136
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"");
1
137
    EXPECT_EQ(test_who[1], iDomConst::FREE);
1
138
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 1);
1
139
}
/home/cyniu/GIT/malina/iDom_server_OOP/test/iDom_TESTs-CMAKE/../../libs/json/single_include/nlohmann/json.hpp
1
/*
2
    __ _____ _____ _____
3
 __|  |   __|     |   | |  JSON for Modern C++
4
|  |  |__   |  |  | | | |  version 3.2.0
5
|_____|_____|_____|_|___|  https://github.com/nlohmann/json
6
7
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8
SPDX-License-Identifier: MIT
9
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
10
11
Permission is hereby  granted, free of charge, to any  person obtaining a copy
12
of this software and associated  documentation files (the "Software"), to deal
13
in the Software  without restriction, including without  limitation the rights
14
to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
15
copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
16
furnished to do so, subject to the following conditions:
17
18
The above copyright notice and this permission notice shall be included in all
19
copies or substantial portions of the Software.
20
21
THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
22
IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
23
FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
24
AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
25
LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
27
SOFTWARE.
28
*/
29
30
#ifndef NLOHMANN_JSON_HPP
31
#define NLOHMANN_JSON_HPP
32
33
#define NLOHMANN_JSON_VERSION_MAJOR 3
34
#define NLOHMANN_JSON_VERSION_MINOR 2
35
#define NLOHMANN_JSON_VERSION_PATCH 0
36
37
#include <algorithm> // all_of, find, for_each
38
#include <cassert> // assert
39
#include <ciso646> // and, not, or
40
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
41
#include <functional> // hash, less
42
#include <initializer_list> // initializer_list
43
#include <iosfwd> // istream, ostream
44
#include <iterator> // iterator_traits, random_access_iterator_tag
45
#include <numeric> // accumulate
46
#include <string> // string, stoi, to_string
47
#include <utility> // declval, forward, move, pair, swap
48
49
// #include <nlohmann/json_fwd.hpp>
50
#ifndef NLOHMANN_JSON_FWD_HPP
51
#define NLOHMANN_JSON_FWD_HPP
52
53
#include <cstdint> // int64_t, uint64_t
54
#include <map> // map
55
#include <memory> // allocator
56
#include <string> // string
57
#include <vector> // vector
58
59
/*!
60
@brief namespace for Niels Lohmann
61
@see https://github.com/nlohmann
62
@since version 1.0.0
63
*/
64
namespace nlohmann
65
{
66
/*!
67
@brief default JSONSerializer template argument
68
69
This serializer ignores the template arguments and uses ADL
70
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
71
for serialization.
72
*/
73
template<typename T = void, typename SFINAE = void>
74
struct adl_serializer;
75
76
template<template<typename U, typename V, typename... Args> class ObjectType =
77
         std::map,
78
         template<typename U, typename... Args> class ArrayType = std::vector,
79
         class StringType = std::string, class BooleanType = bool,
80
         class NumberIntegerType = std::int64_t,
81
         class NumberUnsignedType = std::uint64_t,
82
         class NumberFloatType = double,
83
         template<typename U> class AllocatorType = std::allocator,
84
         template<typename T, typename SFINAE = void> class JSONSerializer =
85
         adl_serializer>
86
class basic_json;
87
88
/*!
89
@brief JSON Pointer
90
91
A JSON pointer defines a string syntax for identifying a specific value
92
within a JSON document. It can be used with functions `at` and
93
`operator[]`. Furthermore, JSON pointers are the base for JSON patches.
94
95
@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
96
97
@since version 2.0.0
98
*/
99
template<typename BasicJsonType>
100
class json_pointer;
101
102
/*!
103
@brief default JSON class
104
105
This type is the default specialization of the @ref basic_json class which
106
uses the standard template types.
107
108
@since version 1.0.0
109
*/
110
using json = basic_json<>;
111
}
112
113
#endif
114
115
// #include <nlohmann/detail/macro_scope.hpp>
116
117
118
// This file contains all internal macro definitions
119
// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
120
121
// exclude unsupported compilers
122
#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
123
    #if defined(__clang__)
124
        #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
125
            #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
126
        #endif
127
    #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
128
        #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
129
            #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
130
        #endif
131
    #endif
132
#endif
133
134
// disable float-equal warnings on GCC/clang
135
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
136
    #pragma GCC diagnostic push
137
    #pragma GCC diagnostic ignored "-Wfloat-equal"
138
#endif
139
140
// disable documentation warnings on clang
141
#if defined(__clang__)
142
    #pragma GCC diagnostic push
143
    #pragma GCC diagnostic ignored "-Wdocumentation"
144
#endif
145
146
// allow for portable deprecation warnings
147
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
148
    #define JSON_DEPRECATED __attribute__((deprecated))
149
#elif defined(_MSC_VER)
150
    #define JSON_DEPRECATED __declspec(deprecated)
151
#else
152
    #define JSON_DEPRECATED
153
#endif
154
155
// allow to disable exceptions
156
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
153
157
    #define JSON_THROW(exception) throw exception
4.04k
158
    #define JSON_TRY try
159
    #define JSON_CATCH(exception) catch(exception)
160
    #define JSON_INTERNAL_CATCH(exception) catch(exception)
161
#else
162
    #define JSON_THROW(exception) std::abort()
163
    #define JSON_TRY if(true)
164
    #define JSON_CATCH(exception) if(false)
165
    #define JSON_INTERNAL_CATCH(exception) if(false)
166
#endif
167
168
// override exception macros
169
#if defined(JSON_THROW_USER)
170
    #undef JSON_THROW
171
    #define JSON_THROW JSON_THROW_USER
172
#endif
173
#if defined(JSON_TRY_USER)
174
    #undef JSON_TRY
175
    #define JSON_TRY JSON_TRY_USER
176
#endif
177
#if defined(JSON_CATCH_USER)
178
    #undef JSON_CATCH
179
    #define JSON_CATCH JSON_CATCH_USER
180
    #undef JSON_INTERNAL_CATCH
181
    #define JSON_INTERNAL_CATCH JSON_CATCH_USER
182
#endif
183
#if defined(JSON_INTERNAL_CATCH_USER)
184
    #undef JSON_INTERNAL_CATCH
185
    #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
186
#endif
187
188
// manual branch prediction
189
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
2.64M
190
    #define JSON_LIKELY(x)      __builtin_expect(!!(x), 1)
344k
191
    #define JSON_UNLIKELY(x)    __builtin_expect(!!(x), 0)
192
#else
193
    #define JSON_LIKELY(x)      x
194
    #define JSON_UNLIKELY(x)    x
195
#endif
196
197
// C++ language standard detection
198
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
199
    #define JSON_HAS_CPP_17
200
    #define JSON_HAS_CPP_14
201
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
202
    #define JSON_HAS_CPP_14
203
#endif
204
205
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
206
// may be removed in the future once the class is split.
207
208
#define NLOHMANN_BASIC_JSON_TPL_DECLARATION                                \
209
    template<template<typename, typename, typename...> class ObjectType,   \
210
             template<typename, typename...> class ArrayType,              \
211
             class StringType, class BooleanType, class NumberIntegerType, \
212
             class NumberUnsignedType, class NumberFloatType,              \
213
             template<typename> class AllocatorType,                       \
214
             template<typename, typename = void> class JSONSerializer>
215
216
#define NLOHMANN_BASIC_JSON_TPL                                            \
217
    basic_json<ObjectType, ArrayType, StringType, BooleanType,             \
218
    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \
219
    AllocatorType, JSONSerializer>
220
221
// #include <nlohmann/detail/meta/cpp_future.hpp>
222
223
224
#include <ciso646> // not
225
#include <cstddef> // size_t
226
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
227
228
namespace nlohmann
229
{
230
namespace detail
231
{
232
// alias templates to reduce boilerplate
233
template<bool B, typename T = void>
234
using enable_if_t = typename std::enable_if<B, T>::type;
235
236
template<typename T>
237
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
238
239
// implementation of C++14 index_sequence and affiliates
240
// source: https://stackoverflow.com/a/32223343
241
template<std::size_t... Ints>
242
struct index_sequence
243
{
244
    using type = index_sequence;
245
    using value_type = std::size_t;
246
    static constexpr std::size_t size() noexcept
247
    {
248
        return sizeof...(Ints);
249
    }
250
};
251
252
template<class Sequence1, class Sequence2>
253
struct merge_and_renumber;
254
255
template<std::size_t... I1, std::size_t... I2>
256
struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
257
        : index_sequence < I1..., (sizeof...(I1) + I2)... > {};
258
259
template<std::size_t N>
260
struct make_index_sequence
261
    : merge_and_renumber < typename make_index_sequence < N / 2 >::type,
262
      typename make_index_sequence < N - N / 2 >::type > {};
263
264
template<> struct make_index_sequence<0> : index_sequence<> {};
265
template<> struct make_index_sequence<1> : index_sequence<0> {};
266
267
template<typename... Ts>
268
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
269
270
// dispatch utility (taken from ranges-v3)
271
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
272
template<> struct priority_tag<0> {};
273
274
// taken from ranges-v3
275
template<typename T>
276
struct static_const
277
{
278
    static constexpr T value{};
279
};
280
281
template<typename T>
282
constexpr T static_const<T>::value;
283
}
284
}
285
286
// #include <nlohmann/detail/meta/type_traits.hpp>
287
288
289
#include <ciso646> // not
290
#include <limits> // numeric_limits
291
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
292
#include <utility> // declval
293
294
// #include <nlohmann/json_fwd.hpp>
295
296
// #include <nlohmann/detail/meta/cpp_future.hpp>
297
298
// #include <nlohmann/detail/meta/detected.hpp>
299
300
301
#include <type_traits>
302
303
// #include <nlohmann/detail/meta/void_t.hpp>
304
305
306
namespace nlohmann
307
{
308
namespace detail
309
{
310
template <typename ...Ts> struct make_void
311
{
312
    using type = void;
313
};
314
template <typename ...Ts> using void_t = typename make_void<Ts...>::type;
315
}
316
}
317
318
319
// http://en.cppreference.com/w/cpp/experimental/is_detected
320
namespace nlohmann
321
{
322
namespace detail
323
{
324
struct nonesuch
325
{
326
    nonesuch() = delete;
327
    ~nonesuch() = delete;
328
    nonesuch(nonesuch const&) = delete;
329
    void operator=(nonesuch const&) = delete;
330
};
331
332
template <class Default,
333
          class AlwaysVoid,
334
          template <class...> class Op,
335
          class... Args>
336
struct detector
337
{
338
    using value_t = std::false_type;
339
    using type = Default;
340
};
341
342
template <class Default, template <class...> class Op, class... Args>
343
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
344
{
345
    using value_t = std::true_type;
346
    using type = Op<Args...>;
347
};
348
349
template <template <class...> class Op, class... Args>
350
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
351
352
template <template <class...> class Op, class... Args>
353
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
354
355
template <class Default, template <class...> class Op, class... Args>
356
using detected_or = detector<Default, void, Op, Args...>;
357
358
template <class Default, template <class...> class Op, class... Args>
359
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
360
361
template <class Expected, template <class...> class Op, class... Args>
362
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
363
364
template <class To, template <class...> class Op, class... Args>
365
using is_detected_convertible =
366
    std::is_convertible<detected_t<Op, Args...>, To>;
367
}
368
}
369
370
// #include <nlohmann/detail/macro_scope.hpp>
371
372
373
namespace nlohmann
374
{
375
/*!
376
@brief detail namespace with internal helper functions
377
378
This namespace collects functions that should not be exposed,
379
implementations of some @ref basic_json methods, and meta-programming helpers.
380
381
@since version 2.1.0
382
*/
383
namespace detail
384
{
385
/////////////
386
// helpers //
387
/////////////
388
389
template<typename> struct is_basic_json : std::false_type {};
390
391
NLOHMANN_BASIC_JSON_TPL_DECLARATION
392
struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
393
394
//////////////////////////
395
// aliases for detected //
396
//////////////////////////
397
398
template <typename T>
399
using mapped_type_t = typename T::mapped_type;
400
401
template <typename T>
402
using key_type_t = typename T::key_type;
403
404
template <typename T>
405
using value_type_t = typename T::value_type;
406
407
template <typename T>
408
using difference_type_t = typename T::difference_type;
409
410
template <typename T>
411
using pointer_t = typename T::pointer;
412
413
template <typename T>
414
using reference_t = typename T::reference;
415
416
template <typename T>
417
using iterator_category_t = typename T::iterator_category;
418
419
template <typename T>
420
using iterator_t = typename T::iterator;
421
422
template <typename T, typename... Args>
423
using to_json_function = decltype(T::to_json(std::declval<Args>()...));
424
425
template <typename T, typename... Args>
426
using from_json_function = decltype(T::from_json(std::declval<Args>()...));
427
428
///////////////////
429
// is_ functions //
430
///////////////////
431
432
template <typename T, typename = void>
433
struct is_iterator_traits : std::false_type {};
434
435
template <typename T>
436
struct is_iterator_traits<std::iterator_traits<T>>
437
{
438
  private:
439
    using traits = std::iterator_traits<T>;
440
441
  public:
442
    static constexpr auto value =
443
        is_detected<value_type_t, traits>::value &&
444
        is_detected<difference_type_t, traits>::value &&
445
        is_detected<pointer_t, traits>::value &&
446
        is_detected<iterator_category_t, traits>::value &&
447
        is_detected<reference_t, traits>::value;
448
};
449
450
// source: https://stackoverflow.com/a/37193089/4116453
451
452
template <typename T, typename = void>
453
struct is_complete_type : std::false_type {};
454
455
template <typename T>
456
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
457
458
template <typename BasicJsonType, typename CompatibleObjectType,
459
          typename = void>
460
struct is_compatible_object_type_impl : std::false_type {};
461
462
template <typename BasicJsonType, typename CompatibleObjectType>
463
struct is_compatible_object_type_impl <
464
    BasicJsonType, CompatibleObjectType,
465
    enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and
466
    is_detected<key_type_t, CompatibleObjectType>::value >>
467
{
468
469
    using object_t = typename BasicJsonType::object_t;
470
471
    // macOS's is_constructible does not play well with nonesuch...
472
    static constexpr bool value =
473
        std::is_constructible<typename object_t::key_type,
474
        typename CompatibleObjectType::key_type>::value and
475
        std::is_constructible<typename object_t::mapped_type,
476
        typename CompatibleObjectType::mapped_type>::value;
477
};
478
479
template <typename BasicJsonType, typename CompatibleObjectType>
480
struct is_compatible_object_type
481
    : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
482
483
template <typename BasicJsonType, typename CompatibleStringType,
484
          typename = void>
485
struct is_compatible_string_type_impl : std::false_type {};
486
487
template <typename BasicJsonType, typename CompatibleStringType>
488
struct is_compatible_string_type_impl <
489
    BasicJsonType, CompatibleStringType,
490
    enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
491
    value_type_t, CompatibleStringType>::value >>
492
{
493
    static constexpr auto value =
494
        std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
495
};
496
497
template <typename BasicJsonType, typename CompatibleStringType>
498
struct is_compatible_string_type
499
    : is_compatible_string_type_impl<BasicJsonType, CompatibleStringType> {};
500
501
template <typename BasicJsonType, typename CompatibleArrayType, typename = void>
502
struct is_compatible_array_type_impl : std::false_type {};
503
504
template <typename BasicJsonType, typename CompatibleArrayType>
505
struct is_compatible_array_type_impl <
506
    BasicJsonType, CompatibleArrayType,
507
    enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and
508
    is_detected<iterator_t, CompatibleArrayType>::value >>
509
{
510
    // This is needed because json_reverse_iterator has a ::iterator type...
511
    // Therefore it is detected as a CompatibleArrayType.
512
    // The real fix would be to have an Iterable concept.
513
    static constexpr bool value = not is_iterator_traits<std::iterator_traits<CompatibleArrayType>>::value;
514
};
515
516
template <typename BasicJsonType, typename CompatibleArrayType>
517
struct is_compatible_array_type
518
    : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
519
520
template <typename RealIntegerType, typename CompatibleNumberIntegerType,
521
          typename = void>
522
struct is_compatible_integer_type_impl : std::false_type {};
523
524
template <typename RealIntegerType, typename CompatibleNumberIntegerType>
525
struct is_compatible_integer_type_impl <
526
    RealIntegerType, CompatibleNumberIntegerType,
527
    enable_if_t<std::is_integral<RealIntegerType>::value and
528
    std::is_integral<CompatibleNumberIntegerType>::value and
529
    not std::is_same<bool, CompatibleNumberIntegerType>::value >>
530
{
531
    // is there an assert somewhere on overflows?
532
    using RealLimits = std::numeric_limits<RealIntegerType>;
533
    using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
534
535
    static constexpr auto value =
536
        std::is_constructible<RealIntegerType,
537
        CompatibleNumberIntegerType>::value and
538
        CompatibleLimits::is_integer and
539
        RealLimits::is_signed == CompatibleLimits::is_signed;
540
};
541
542
template <typename RealIntegerType, typename CompatibleNumberIntegerType>
543
struct is_compatible_integer_type
544
    : is_compatible_integer_type_impl<RealIntegerType,
545
      CompatibleNumberIntegerType> {};
546
547
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
548
template<typename BasicJsonType, typename T>
549
struct has_from_json
550
{
551
    using serializer = typename BasicJsonType::template json_serializer<T, void>;
552
553
    static constexpr bool value =
554
        is_detected_exact<void, from_json_function, serializer,
555
        const BasicJsonType&, T&>::value;
556
};
557
558
// This trait checks if JSONSerializer<T>::from_json(json const&) exists
559
// this overload is used for non-default-constructible user-defined-types
560
template<typename BasicJsonType, typename T>
561
struct has_non_default_from_json
562
{
563
    using serializer = typename BasicJsonType::template json_serializer<T, void>;
564
565
    static constexpr bool value =
566
        is_detected_exact<T, from_json_function, serializer,
567
        const BasicJsonType&>::value;
568
};
569
570
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
571
template<typename BasicJsonType, typename T>
572
struct has_to_json
573
{
574
    using serializer = typename BasicJsonType::template json_serializer<T, void>;
575
576
    static constexpr bool value =
577
        is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
578
        T>::value;
579
};
580
581
template <typename BasicJsonType, typename CompatibleType, typename = void>
582
struct is_compatible_type_impl: std::false_type {};
583
584
template <typename BasicJsonType, typename CompatibleType>
585
struct is_compatible_type_impl <
586
    BasicJsonType, CompatibleType,
587
    enable_if_t<is_complete_type<CompatibleType>::value >>
588
{
589
    static constexpr bool value =
590
        has_to_json<BasicJsonType, CompatibleType>::value;
591
};
592
593
template <typename BasicJsonType, typename CompatibleType>
594
struct is_compatible_type
595
    : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
596
}
597
}
598
599
// #include <nlohmann/detail/exceptions.hpp>
600
601
602
#include <exception> // exception
603
#include <stdexcept> // runtime_error
604
#include <string> // to_string
605
606
namespace nlohmann
607
{
608
namespace detail
609
{
610
////////////////
611
// exceptions //
612
////////////////
613
614
/*!
615
@brief general exception of the @ref basic_json class
616
617
This class is an extension of `std::exception` objects with a member @a id for
618
exception ids. It is used as the base class for all exceptions thrown by the
619
@ref basic_json class. This class can hence be used as "wildcard" to catch
620
exceptions.
621
622
Subclasses:
623
- @ref parse_error for exceptions indicating a parse error
624
- @ref invalid_iterator for exceptions indicating errors with iterators
625
- @ref type_error for exceptions indicating executing a member function with
626
                  a wrong type
627
- @ref out_of_range for exceptions indicating access out of the defined range
628
- @ref other_error for exceptions indicating other library errors
629
630
@internal
631
@note To have nothrow-copy-constructible exceptions, we internally use
632
      `std::runtime_error` which can cope with arbitrary-length error messages.
633
      Intermediate strings are built with static functions and then passed to
634
      the actual constructor.
635
@endinternal
636
637
@liveexample{The following code shows how arbitrary library exceptions can be
638
caught.,exception}
639
640
@since version 3.0.0
641
*/
642
class exception : public std::exception
643
{
644
  public:
645
    /// returns the explanatory string
646
    const char* what() const noexcept override
0
647
    {
0
648
        return m.what();
0
649
    }
650
651
    /// the id of the exception
652
    const int id;
653
654
  protected:
1
655
    exception(int id_, const char* what_arg) : id(id_), m(what_arg) {}
656
657
    static std::string name(const std::string& ename, int id_)
1
658
    {
1
659
        return "[json.exception." + ename + "." + std::to_string(id_) + "] ";
1
660
    }
661
662
  private:
663
    /// an exception object as storage for error messages
664
    std::runtime_error m;
665
};
666
667
/*!
668
@brief exception indicating a parse error
669
670
This exception is thrown by the library when a parse error occurs. Parse errors
671
can occur during the deserialization of JSON text, CBOR, MessagePack, as well
672
as when using JSON Patch.
673
674
Member @a byte holds the byte index of the last read character in the input
675
file.
676
677
Exceptions have ids 1xx.
678
679
name / id                      | example message | description
680
------------------------------ | --------------- | -------------------------
681
json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position.
682
json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point.
683
json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid.
684
json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.
685
json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors.
686
json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`.
687
json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character.
688
json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences.
689
json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number.
690
json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.
691
json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
692
json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.
693
694
@note For an input with n bytes, 1 is the index of the first character and n+1
695
      is the index of the terminating null byte or the end of file. This also
696
      holds true when reading a byte vector (CBOR or MessagePack).
697
698
@liveexample{The following code shows how a `parse_error` exception can be
699
caught.,parse_error}
700
701
@sa @ref exception for the base class of the library exceptions
702
@sa @ref invalid_iterator for exceptions indicating errors with iterators
703
@sa @ref type_error for exceptions indicating executing a member function with
704
                    a wrong type
705
@sa @ref out_of_range for exceptions indicating access out of the defined range
706
@sa @ref other_error for exceptions indicating other library errors
707
708
@since version 3.0.0
709
*/
710
class parse_error : public exception
711
{
712
  public:
713
    /*!
714
    @brief create a parse error exception
715
    @param[in] id_       the id of the exception
716
    @param[in] byte_     the byte index where the error occurred (or 0 if the
717
                         position cannot be determined)
718
    @param[in] what_arg  the explanatory string
719
    @return parse_error object
720
    */
721
    static parse_error create(int id_, std::size_t byte_, const std::string& what_arg)
0
722
    {
0
723
        std::string w = exception::name("parse_error", id_) + "parse error" +
0
724
                        (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") +
0
725
                        ": " + what_arg;
0
726
        return parse_error(id_, byte_, w.c_str());
0
727
    }
728
729
    /*!
730
    @brief byte index of the parse error
731
732
    The byte index of the last read character in the input file.
733
734
    @note For an input with n bytes, 1 is the index of the first character and
735
          n+1 is the index of the terminating null byte or the end of file.
736
          This also holds true when reading a byte vector (CBOR or MessagePack).
737
    */
738
    const std::size_t byte;
739
740
  private:
741
    parse_error(int id_, std::size_t byte_, const char* what_arg)
0
742
        : exception(id_, what_arg), byte(byte_) {}
743
};
744
745
/*!
746
@brief exception indicating errors with iterators
747
748
This exception is thrown if iterators passed to a library function do not match
749
the expected semantics.
750
751
Exceptions have ids 2xx.
752
753
name / id                           | example message | description
754
----------------------------------- | --------------- | -------------------------
755
json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.
756
json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.
757
json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from.
758
json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid.
759
json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid.
760
json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range.
761
json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key.
762
json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.
763
json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.
764
json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.
765
json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to.
766
json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container.
767
json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered.
768
json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin().
769
770
@liveexample{The following code shows how an `invalid_iterator` exception can be
771
caught.,invalid_iterator}
772
773
@sa @ref exception for the base class of the library exceptions
774
@sa @ref parse_error for exceptions indicating a parse error
775
@sa @ref type_error for exceptions indicating executing a member function with
776
                    a wrong type
777
@sa @ref out_of_range for exceptions indicating access out of the defined range
778
@sa @ref other_error for exceptions indicating other library errors
779
780
@since version 3.0.0
781
*/
782
class invalid_iterator : public exception
783
{
784
  public:
785
    static invalid_iterator create(int id_, const std::string& what_arg)
0
786
    {
0
787
        std::string w = exception::name("invalid_iterator", id_) + what_arg;
0
788
        return invalid_iterator(id_, w.c_str());
0
789
    }
790
791
  private:
792
    invalid_iterator(int id_, const char* what_arg)
0
793
        : exception(id_, what_arg) {}
794
};
795
796
/*!
797
@brief exception indicating executing a member function with a wrong type
798
799
This exception is thrown in case of a type error; that is, a library function is
800
executed on a JSON value whose type does not match the expected semantics.
801
802
Exceptions have ids 3xx.
803
804
name / id                     | example message | description
805
----------------------------- | --------------- | -------------------------
806
json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.
807
json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.
808
json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&.
809
json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.
810
json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.
811
json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.
812
json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types.
813
json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types.
814
json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.
815
json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.
816
json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.
817
json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types.
818
json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.
819
json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.
820
json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.
821
json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. |
822
823
@liveexample{The following code shows how a `type_error` exception can be
824
caught.,type_error}
825
826
@sa @ref exception for the base class of the library exceptions
827
@sa @ref parse_error for exceptions indicating a parse error
828
@sa @ref invalid_iterator for exceptions indicating errors with iterators
829
@sa @ref out_of_range for exceptions indicating access out of the defined range
830
@sa @ref other_error for exceptions indicating other library errors
831
832
@since version 3.0.0
833
*/
834
class type_error : public exception
835
{
836
  public:
837
    static type_error create(int id_, const std::string& what_arg)
0
838
    {
0
839
        std::string w = exception::name("type_error", id_) + what_arg;
0
840
        return type_error(id_, w.c_str());
0
841
    }
842
843
  private:
0
844
    type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
845
};
846
847
/*!
848
@brief exception indicating access out of the defined range
849
850
This exception is thrown in case a library function is called on an input
851
parameter that exceeds the expected range, for instance in case of array
852
indices or nonexisting object keys.
853
854
Exceptions have ids 4xx.
855
856
name / id                       | example message | description
857
------------------------------- | --------------- | -------------------------
858
json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1.
859
json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it.
860
json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object.
861
json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.
862
json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.
863
json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.
864
json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. |
865
json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |
866
867
@liveexample{The following code shows how an `out_of_range` exception can be
868
caught.,out_of_range}
869
870
@sa @ref exception for the base class of the library exceptions
871
@sa @ref parse_error for exceptions indicating a parse error
872
@sa @ref invalid_iterator for exceptions indicating errors with iterators
873
@sa @ref type_error for exceptions indicating executing a member function with
874
                    a wrong type
875
@sa @ref other_error for exceptions indicating other library errors
876
877
@since version 3.0.0
878
*/
879
class out_of_range : public exception
880
{
881
  public:
882
    static out_of_range create(int id_, const std::string& what_arg)
1
883
    {
1
884
        std::string w = exception::name("out_of_range", id_) + what_arg;
1
885
        return out_of_range(id_, w.c_str());
1
886
    }
887
888
  private:
1
889
    out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
890
};
891
892
/*!
893
@brief exception indicating other library errors
894
895
This exception is thrown in case of errors that cannot be classified with the
896
other exception types.
897
898
Exceptions have ids 5xx.
899
900
name / id                      | example message | description
901
------------------------------ | --------------- | -------------------------
902
json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
903
904
@sa @ref exception for the base class of the library exceptions
905
@sa @ref parse_error for exceptions indicating a parse error
906
@sa @ref invalid_iterator for exceptions indicating errors with iterators
907
@sa @ref type_error for exceptions indicating executing a member function with
908
                    a wrong type
909
@sa @ref out_of_range for exceptions indicating access out of the defined range
910
911
@liveexample{The following code shows how an `other_error` exception can be
912
caught.,other_error}
913
914
@since version 3.0.0
915
*/
916
class other_error : public exception
917
{
918
  public:
919
    static other_error create(int id_, const std::string& what_arg)
0
920
    {
0
921
        std::string w = exception::name("other_error", id_) + what_arg;
0
922
        return other_error(id_, w.c_str());
0
923
    }
924
925
  private:
0
926
    other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
927
};
928
}
929
}
930
931
// #include <nlohmann/detail/value_t.hpp>
932
933
934
#include <array> // array
935
#include <ciso646> // and
936
#include <cstddef> // size_t
937
#include <cstdint> // uint8_t
938
939
namespace nlohmann
940
{
941
namespace detail
942
{
943
///////////////////////////
944
// JSON type enumeration //
945
///////////////////////////
946
947
/*!
948
@brief the JSON type enumeration
949
950
This enumeration collects the different JSON types. It is internally used to
951
distinguish the stored values, and the functions @ref basic_json::is_null(),
952
@ref basic_json::is_object(), @ref basic_json::is_array(),
953
@ref basic_json::is_string(), @ref basic_json::is_boolean(),
954
@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
955
@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
956
@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
957
@ref basic_json::is_structured() rely on it.
958
959
@note There are three enumeration entries (number_integer, number_unsigned, and
960
number_float), because the library distinguishes these three types for numbers:
961
@ref basic_json::number_unsigned_t is used for unsigned integers,
962
@ref basic_json::number_integer_t is used for signed integers, and
963
@ref basic_json::number_float_t is used for floating-point numbers or to
964
approximate integers which do not fit in the limits of their respective type.
965
966
@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON
967
value with the default value for a given type
968
969
@since version 1.0.0
970
*/
971
enum class value_t : std::uint8_t
972
{
973
    null,             ///< null value
974
    object,           ///< object (unordered set of name/value pairs)
975
    array,            ///< array (ordered collection of values)
976
    string,           ///< string value
977
    boolean,          ///< boolean value
978
    number_integer,   ///< number value (signed integer)
979
    number_unsigned,  ///< number value (unsigned integer)
980
    number_float,     ///< number value (floating-point)
981
    discarded         ///< discarded by the the parser callback function
982
};
983
984
/*!
985
@brief comparison operator for JSON types
986
987
Returns an ordering that is similar to Python:
988
- order: null < boolean < number < object < array < string
989
- furthermore, each type is not smaller than itself
990
- discarded values are not comparable
991
992
@since version 1.0.0
993
*/
994
inline bool operator<(const value_t lhs, const value_t rhs) noexcept
0
995
{
0
996
    static constexpr std::array<std::uint8_t, 8> order = {{
0
997
            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
0
998
            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */
0
999
        }
0
1000
    };
0
1001
0
1002
    const auto l_index = static_cast<std::size_t>(lhs);
0
1003
    const auto r_index = static_cast<std::size_t>(rhs);
0
1004
    return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index];
0
1005
}
1006
}
1007
}
1008
1009
// #include <nlohmann/detail/conversions/from_json.hpp>
1010
1011
1012
#include <algorithm> // transform
1013
#include <array> // array
1014
#include <ciso646> // and, not
1015
#include <forward_list> // forward_list
1016
#include <iterator> // inserter, front_inserter, end
1017
#include <map> // map
1018
#include <string> // string
1019
#include <tuple> // tuple, make_tuple
1020
#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
1021
#include <unordered_map> // unordered_map
1022
#include <utility> // pair, declval
1023
#include <valarray> // valarray
1024
1025
// #include <nlohmann/detail/exceptions.hpp>
1026
1027
// #include <nlohmann/detail/macro_scope.hpp>
1028
1029
// #include <nlohmann/detail/meta/cpp_future.hpp>
1030
1031
// #include <nlohmann/detail/meta/type_traits.hpp>
1032
1033
// #include <nlohmann/detail/value_t.hpp>
1034
1035
1036
namespace nlohmann
1037
{
1038
namespace detail
1039
{
1040
template<typename BasicJsonType>
1041
void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
1042
{
1043
    if (JSON_UNLIKELY(not j.is_null()))
1044
    {
1045
        JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name())));
1046
    }
1047
    n = nullptr;
1048
}
1049
1050
// overloads for basic_json template parameters
1051
template<typename BasicJsonType, typename ArithmeticType,
1052
         enable_if_t<std::is_arithmetic<ArithmeticType>::value and
1053
                     not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
1054
                     int> = 0>
1055
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
148
1056
{
148
1057
    switch (static_cast<value_t>(j))
148
1058
    {
0
1059
        case value_t::number_unsigned:
0
1060
        {
0
1061
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
0
1062
            break;
0
1063
        }
0
1064
        case value_t::number_integer:
0
1065
        {
0
1066
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
0
1067
            break;
0
1068
        }
148
1069
        case value_t::number_float:
148
1070
        {
148
1071
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
148
1072
            break;
0
1073
        }
0
1074
0
1075
        default:
0
1076
            JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name())));
148
1077
    }
148
1078
}
1079
1080
template<typename BasicJsonType>
1081
void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
2
1082
{
2
1083
    if (JSON_UNLIKELY(not j.is_boolean()))
0
1084
    {
0
1085
        JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name())));
0
1086
    }
2
1087
    b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
2
1088
}
1089
1090
template<typename BasicJsonType>
1091
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
3.26k
1092
{
3.26k
1093
    if (JSON_UNLIKELY(not j.is_string()))
0
1094
    {
0
1095
        JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
0
1096
    }
3.26k
1097
    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
3.26k
1098
}
1099
1100
template <
1101
    typename BasicJsonType, typename CompatibleStringType,
1102
    enable_if_t <
1103
        is_compatible_string_type<BasicJsonType, CompatibleStringType>::value and
1104
        not std::is_same<typename BasicJsonType::string_t,
1105
                         CompatibleStringType>::value,
1106
        int > = 0 >
1107
void from_json(const BasicJsonType& j, CompatibleStringType& s)
1108
{
1109
    if (JSON_UNLIKELY(not j.is_string()))
1110
    {
1111
        JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
1112
    }
1113
1114
    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
1115
}
1116
1117
template<typename BasicJsonType>
1118
void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
148
1119
{
148
1120
    get_arithmetic_value(j, val);
148
1121
}
1122
1123
template<typename BasicJsonType>
1124
void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
1125
{
1126
    get_arithmetic_value(j, val);
1127
}
1128
1129
template<typename BasicJsonType>
1130
void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
1131
{
1132
    get_arithmetic_value(j, val);
1133
}
1134
1135
template<typename BasicJsonType, typename EnumType,
1136
         enable_if_t<std::is_enum<EnumType>::value, int> = 0>
1137
void from_json(const BasicJsonType& j, EnumType& e)
1138
{
1139
    typename std::underlying_type<EnumType>::type val;
1140
    get_arithmetic_value(j, val);
1141
    e = static_cast<EnumType>(val);
1142
}
1143
1144
// forward_list doesn't have an insert method
1145
template<typename BasicJsonType, typename T, typename Allocator,
1146
         enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
1147
void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
1148
{
1149
    if (JSON_UNLIKELY(not j.is_array()))
1150
    {
1151
        JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
1152
    }
1153
    std::transform(j.rbegin(), j.rend(),
1154
                   std::front_inserter(l), [](const BasicJsonType & i)
1155
    {
1156
        return i.template get<T>();
1157
    });
1158
}
1159
1160
// valarray doesn't have an insert method
1161
template<typename BasicJsonType, typename T,
1162
         enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
1163
void from_json(const BasicJsonType& j, std::valarray<T>& l)
1164
{
1165
    if (JSON_UNLIKELY(not j.is_array()))
1166
    {
1167
        JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
1168
    }
1169
    l.resize(j.size());
1170
    std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l));
1171
}
1172
1173
template<typename BasicJsonType>
1174
void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
1175
{
1176
    arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
1177
}
1178
1179
template <typename BasicJsonType, typename T, std::size_t N>
1180
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
1181
                          priority_tag<2> /*unused*/)
1182
-> decltype(j.template get<T>(), void())
1183
{
1184
    for (std::size_t i = 0; i < N; ++i)
1185
    {
1186
        arr[i] = j.at(i).template get<T>();
1187
    }
1188
}
1189
1190
template<typename BasicJsonType, typename CompatibleArrayType>
1191
auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/)
1192
-> decltype(
1193
    arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
1194
    j.template get<typename CompatibleArrayType::value_type>(),
1195
    void())
1196
{
1197
    using std::end;
1198
1199
    arr.reserve(j.size());
1200
    std::transform(j.begin(), j.end(),
1201
                   std::inserter(arr, end(arr)), [](const BasicJsonType & i)
1202
    {
1203
        // get<BasicJsonType>() returns *this, this won't call a from_json
1204
        // method when value_type is BasicJsonType
1205
        return i.template get<typename CompatibleArrayType::value_type>();
1206
    });
1207
}
1208
1209
template <typename BasicJsonType, typename CompatibleArrayType>
1210
void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr,
1211
                          priority_tag<0> /*unused*/)
1212
{
1213
    using std::end;
1214
1215
    std::transform(
1216
        j.begin(), j.end(), std::inserter(arr, end(arr)),
1217
        [](const BasicJsonType & i)
1218
    {
1219
        // get<BasicJsonType>() returns *this, this won't call a from_json
1220
        // method when value_type is BasicJsonType
1221
        return i.template get<typename CompatibleArrayType::value_type>();
1222
    });
1223
}
1224
1225
template <typename BasicJsonType, typename CompatibleArrayType,
1226
          enable_if_t <
1227
              is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
1228
              not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and
1229
              not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
1230
              not is_basic_json<CompatibleArrayType>::value,
1231
              int > = 0 >
1232
1233
auto from_json(const BasicJsonType& j, CompatibleArrayType& arr)
1234
-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
1235
j.template get<typename CompatibleArrayType::value_type>(),
1236
void())
1237
{
1238
    if (JSON_UNLIKELY(not j.is_array()))
1239
    {
1240
        JSON_THROW(type_error::create(302, "type must be array, but is " +
1241
                                      std::string(j.type_name())));
1242
    }
1243
1244
    from_json_array_impl(j, arr, priority_tag<3> {});
1245
}
1246
1247
template<typename BasicJsonType, typename CompatibleObjectType,
1248
         enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0>
1249
void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
1250
{
1251
    if (JSON_UNLIKELY(not j.is_object()))
1252
    {
1253
        JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name())));
1254
    }
1255
1256
    auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
1257
    using value_type = typename CompatibleObjectType::value_type;
1258
    std::transform(
1259
        inner_object->begin(), inner_object->end(),
1260
        std::inserter(obj, obj.begin()),
1261
        [](typename BasicJsonType::object_t::value_type const & p)
1262
    {
1263
        return value_type(p.first, p.second.template get<typename CompatibleObjectType::mapped_type>());
1264
    });
1265
}
1266
1267
// overload for arithmetic types, not chosen for basic_json template arguments
1268
// (BooleanType, etc..); note: Is it really necessary to provide explicit
1269
// overloads for boolean_t etc. in case of a custom BooleanType which is not
1270
// an arithmetic type?
1271
template<typename BasicJsonType, typename ArithmeticType,
1272
         enable_if_t <
1273
             std::is_arithmetic<ArithmeticType>::value and
1274
             not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and
1275
             not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and
1276
             not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and
1277
             not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
1278
             int> = 0>
1279
void from_json(const BasicJsonType& j, ArithmeticType& val)
152
1280
{
152
1281
    switch (static_cast<value_t>(j))
152
1282
    {
152
1283
        case value_t::number_unsigned:
152
1284
        {
152
1285
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
152
1286
            break;
152
1287
        }
0
1288
        case value_t::number_integer:
0
1289
        {
0
1290
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
0
1291
            break;
152
1292
        }
0
1293
        case value_t::number_float:
0
1294
        {
0
1295
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
0
1296
            break;
152
1297
        }
0
1298
        case value_t::boolean:
0
1299
        {
0
1300
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
0
1301
            break;
152
1302
        }
152
1303
0
1304
        default:
0
1305
            JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name())));
152
1306
    }
152
1307
}
1308
1309
template<typename BasicJsonType, typename A1, typename A2>
1310
void from_json(const BasicJsonType& j, std::pair<A1, A2>& p)
1311
{
1312
    p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};
1313
}
1314
1315
template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
1316
void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...>)
1317
{
1318
    t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);
1319
}
1320
1321
template<typename BasicJsonType, typename... Args>
1322
void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
1323
{
1324
    from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
1325
}
1326
1327
template <typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
1328
          typename = enable_if_t<not std::is_constructible<
1329
                                     typename BasicJsonType::string_t, Key>::value>>
1330
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
1331
{
1332
    if (JSON_UNLIKELY(not j.is_array()))
1333
    {
1334
        JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
1335
    }
1336
    for (const auto& p : j)
1337
    {
1338
        if (JSON_UNLIKELY(not p.is_array()))
1339
        {
1340
            JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
1341
        }
1342
        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
1343
    }
1344
}
1345
1346
template <typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
1347
          typename = enable_if_t<not std::is_constructible<
1348
                                     typename BasicJsonType::string_t, Key>::value>>
1349
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
1350
{
1351
    if (JSON_UNLIKELY(not j.is_array()))
1352
    {
1353
        JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
1354
    }
1355
    for (const auto& p : j)
1356
    {
1357
        if (JSON_UNLIKELY(not p.is_array()))
1358
        {
1359
            JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
1360
        }
1361
        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
1362
    }
1363
}
1364
1365
struct from_json_fn
1366
{
1367
    template<typename BasicJsonType, typename T>
1368
    auto operator()(const BasicJsonType& j, T& val) const
1369
    noexcept(noexcept(from_json(j, val)))
1370
    -> decltype(from_json(j, val), void())
3.56k
1371
    {
3.56k
1372
        return from_json(j, val);
3.56k
1373
    }
_ZNK8nlohmann6detail12from_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEiEEDTcmcl9from_jsonfp_fp0_Ecvv_EERKT_RT0_
152
1371
    {
152
1372
        return from_json(j, val);
152
1373
    }
_ZNK8nlohmann6detail12from_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEESB_EEDTcmcl9from_jsonfp_fp0_Ecvv_EERKT_RT0_
3.26k
1371
    {
3.26k
1372
        return from_json(j, val);
3.26k
1373
    }
_ZNK8nlohmann6detail12from_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEbEEDTcmcl9from_jsonfp_fp0_Ecvv_EERKT_RT0_
2
1371
    {
2
1372
        return from_json(j, val);
2
1373
    }
_ZNK8nlohmann6detail12from_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEdEEDTcmcl9from_jsonfp_fp0_Ecvv_EERKT_RT0_
148
1371
    {
148
1372
        return from_json(j, val);
148
1373
    }
1374
};
1375
}
1376
1377
/// namespace to hold default `from_json` function
1378
/// to see why this is required:
1379
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
1380
namespace
1381
{
1382
constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;
1383
}
1384
}
1385
1386
// #include <nlohmann/detail/conversions/to_json.hpp>
1387
1388
1389
#include <ciso646> // or, and, not
1390
#include <iterator> // begin, end
1391
#include <tuple> // tuple, get
1392
#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
1393
#include <utility> // move, forward, declval, pair
1394
#include <valarray> // valarray
1395
#include <vector> // vector
1396
1397
// #include <nlohmann/detail/meta/cpp_future.hpp>
1398
1399
// #include <nlohmann/detail/meta/type_traits.hpp>
1400
1401
// #include <nlohmann/detail/value_t.hpp>
1402
1403
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
1404
1405
1406
#include <cstddef> // size_t
1407
#include <string> // string, to_string
1408
#include <iterator> // input_iterator_tag
1409
1410
// #include <nlohmann/detail/value_t.hpp>
1411
1412
1413
namespace nlohmann
1414
{
1415
namespace detail
1416
{
1417
/// proxy class for the items() function
1418
template<typename IteratorType> class iteration_proxy
1419
{
1420
  private:
1421
    /// helper class for iteration
1422
    class iteration_proxy_internal
1423
    {
1424
      public:
1425
        using difference_type = std::ptrdiff_t;
1426
        using value_type = iteration_proxy_internal;
1427
        using pointer = iteration_proxy_internal*;
1428
        using reference = iteration_proxy_internal&;
1429
        using iterator_category = std::input_iterator_tag;
1430
1431
      private:
1432
        /// the iterator
1433
        IteratorType anchor;
1434
        /// an index for arrays (used to create key names)
1435
        std::size_t array_index = 0;
1436
        /// last stringified array index
1437
        mutable std::size_t array_index_last = 0;
1438
        /// a string representation of the array index
1439
        mutable std::string array_index_str = "0";
1440
        /// an empty string (to return a reference for primitive values)
1441
        const std::string empty_str = "";
1442
1443
      public:
0
1444
        explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {}
1445
1446
        iteration_proxy_internal(const iteration_proxy_internal&) = default;
1447
        iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default;
1448
1449
        /// dereference operator (needed for range-based for)
1450
        iteration_proxy_internal& operator*()
0
1451
        {
0
1452
            return *this;
0
1453
        }
1454
1455
        /// increment operator (needed for range-based for)
1456
        iteration_proxy_internal& operator++()
0
1457
        {
0
1458
            ++anchor;
0
1459
            ++array_index;
0
1460
0
1461
            return *this;
0
1462
        }
1463
1464
        /// equality operator (needed for InputIterator)
1465
        bool operator==(const iteration_proxy_internal& o) const noexcept
0
1466
        {
0
1467
            return anchor == o.anchor;
0
1468
        }
1469
1470
        /// inequality operator (needed for range-based for)
1471
        bool operator!=(const iteration_proxy_internal& o) const noexcept
0
1472
        {
0
1473
            return anchor != o.anchor;
0
1474
        }
1475
1476
        /// return key of the iterator
1477
        const std::string& key() const
0
1478
        {
0
1479
            assert(anchor.m_object != nullptr);
0
1480
0
1481
            switch (anchor.m_object->type())
0
1482
            {
0
1483
                // use integer array index as key
0
1484
                case value_t::array:
0
1485
                {
0
1486
                    if (array_index != array_index_last)
0
1487
                    {
0
1488
                        array_index_str = std::to_string(array_index);
0
1489
                        array_index_last = array_index;
0
1490
                    }
0
1491
                    return array_index_str;
0
1492
                }
0
1493
0
1494
                // use key from the object
0
1495
                case value_t::object:
0
1496
                    return anchor.key();
0
1497
0
1498
                // use an empty key for all primitive types
0
1499
                default:
0
1500
                    return empty_str;
0
1501
            }
0
1502
        }
1503
1504
        /// return value of the iterator
1505
        typename IteratorType::reference value() const
0
1506
        {
0
1507
            return anchor.value();
0
1508
        }
1509
    };
1510
1511
    /// the container to iterate
1512
    typename IteratorType::reference container;
1513
1514
  public:
1515
    /// construct iteration proxy from a container
1516
    explicit iteration_proxy(typename IteratorType::reference cont) noexcept
1517
        : container(cont) {}
1518
1519
    /// return iterator begin (needed for range-based for)
1520
    iteration_proxy_internal begin() noexcept
1521
    {
1522
        return iteration_proxy_internal(container.begin());
1523
    }
1524
1525
    /// return iterator end (needed for range-based for)
1526
    iteration_proxy_internal end() noexcept
1527
    {
1528
        return iteration_proxy_internal(container.end());
1529
    }
1530
};
1531
}
1532
}
1533
1534
1535
namespace nlohmann
1536
{
1537
namespace detail
1538
{
1539
//////////////////
1540
// constructors //
1541
//////////////////
1542
1543
template<value_t> struct external_constructor;
1544
1545
template<>
1546
struct external_constructor<value_t::boolean>
1547
{
1548
    template<typename BasicJsonType>
1549
    static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
180
1550
    {
180
1551
        j.m_type = value_t::boolean;
180
1552
        j.m_value = b;
180
1553
        j.assert_invariant();
180
1554
    }
1555
};
1556
1557
template<>
1558
struct external_constructor<value_t::string>
1559
{
1560
    template<typename BasicJsonType>
1561
    static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
18.3k
1562
    {
18.3k
1563
        j.m_type = value_t::string;
18.3k
1564
        j.m_value = s;
18.3k
1565
        j.assert_invariant();
18.3k
1566
    }
1567
1568
    template<typename BasicJsonType>
1569
    static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
144
1570
    {
144
1571
        j.m_type = value_t::string;
144
1572
        j.m_value = std::move(s);
144
1573
        j.assert_invariant();
144
1574
    }
1575
1576
    template<typename BasicJsonType, typename CompatibleStringType,
1577
             enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
1578
                         int> = 0>
1579
    static void construct(BasicJsonType& j, const CompatibleStringType& str)
69
1580
    {
69
1581
        j.m_type = value_t::string;
69
1582
        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
69
1583
        j.assert_invariant();
69
1584
    }
_ZN8nlohmann6detail20external_constructorILNS0_7value_tE3EE9constructINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEA6_cLi0EEEvRT_RKT0_
1
1580
    {
1
1581
        j.m_type = value_t::string;
1
1582
        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
1
1583
        j.assert_invariant();
1
1584
    }
_ZN8nlohmann6detail20external_constructorILNS0_7value_tE3EE9constructINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEPKcLi0EEEvRT_RKT0_
10
1580
    {
10
1581
        j.m_type = value_t::string;
10
1582
        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
10
1583
        j.assert_invariant();
10
1584
    }
_ZN8nlohmann6detail20external_constructorILNS0_7value_tE3EE9constructINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEA474_cLi0EEEvRT_RKT0_
58
1580
    {
58
1581
        j.m_type = value_t::string;
58
1582
        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
58
1583
        j.assert_invariant();
58
1584
    }
1585
};
1586
1587
template<>
1588
struct external_constructor<value_t::number_float>
1589
{
1590
    template<typename BasicJsonType>
1591
    static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
16.8k
1592
    {
16.8k
1593
        j.m_type = value_t::number_float;
16.8k
1594
        j.m_value = val;
16.8k
1595
        j.assert_invariant();
16.8k
1596
    }
1597
};
1598
1599
template<>
1600
struct external_constructor<value_t::number_unsigned>
1601
{
1602
    template<typename BasicJsonType>
1603
    static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
22.6k
1604
    {
22.6k
1605
        j.m_type = value_t::number_unsigned;
22.6k
1606
        j.m_value = val;
22.6k
1607
        j.assert_invariant();
22.6k
1608
    }
1609
};
1610
1611
template<>
1612
struct external_constructor<value_t::number_integer>
1613
{
1614
    template<typename BasicJsonType>
1615
    static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
2.69k
1616
    {
2.69k
1617
        j.m_type = value_t::number_integer;
2.69k
1618
        j.m_value = val;
2.69k
1619
        j.assert_invariant();
2.69k
1620
    }
1621
};
1622
1623
template<>
1624
struct external_constructor<value_t::array>
1625
{
1626
    template<typename BasicJsonType>
1627
    static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
1628
    {
1629
        j.m_type = value_t::array;
1630
        j.m_value = arr;
1631
        j.assert_invariant();
1632
    }
1633
1634
    template<typename BasicJsonType>
1635
    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
1636
    {
1637
        j.m_type = value_t::array;
1638
        j.m_value = std::move(arr);
1639
        j.assert_invariant();
1640
    }
1641
1642
    template<typename BasicJsonType, typename CompatibleArrayType,
1643
             enable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
1644
                         int> = 0>
1645
    static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
1646
    {
1647
        using std::begin;
1648
        using std::end;
1649
        j.m_type = value_t::array;
1650
        j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
1651
        j.assert_invariant();
1652
    }
1653
1654
    template<typename BasicJsonType>
1655
    static void construct(BasicJsonType& j, const std::vector<bool>& arr)
1656
    {
1657
        j.m_type = value_t::array;
1658
        j.m_value = value_t::array;
1659
        j.m_value.array->reserve(arr.size());
1660
        for (const bool x : arr)
1661
        {
1662
            j.m_value.array->push_back(x);
1663
        }
1664
        j.assert_invariant();
1665
    }
1666
1667
    template<typename BasicJsonType, typename T,
1668
             enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
1669
    static void construct(BasicJsonType& j, const std::valarray<T>& arr)
1670
    {
1671
        j.m_type = value_t::array;
1672
        j.m_value = value_t::array;
1673
        j.m_value.array->resize(arr.size());
1674
        std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
1675
        j.assert_invariant();
1676
    }
1677
};
1678
1679
template<>
1680
struct external_constructor<value_t::object>
1681
{
1682
    template<typename BasicJsonType>
1683
    static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
1684
    {
1685
        j.m_type = value_t::object;
1686
        j.m_value = obj;
1687
        j.assert_invariant();
1688
    }
1689
1690
    template<typename BasicJsonType>
1691
    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
1692
    {
1693
        j.m_type = value_t::object;
1694
        j.m_value = std::move(obj);
1695
        j.assert_invariant();
1696
    }
1697
1698
    template<typename BasicJsonType, typename CompatibleObjectType,
1699
             enable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0>
1700
    static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
1701
    {
1702
        using std::begin;
1703
        using std::end;
1704
1705
        j.m_type = value_t::object;
1706
        j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
1707
        j.assert_invariant();
1708
    }
1709
};
1710
1711
/////////////
1712
// to_json //
1713
/////////////
1714
1715
template<typename BasicJsonType, typename T,
1716
         enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
1717
void to_json(BasicJsonType& j, T b) noexcept
180
1718
{
180
1719
    external_constructor<value_t::boolean>::construct(j, b);
180
1720
}
1721
1722
template<typename BasicJsonType, typename CompatibleString,
1723
         enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
1724
void to_json(BasicJsonType& j, const CompatibleString& s)
18.4k
1725
{
18.4k
1726
    external_constructor<value_t::string>::construct(j, s);
18.4k
1727
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEESA_Li0EEEvRT_RKT0_
18.3k
1725
{
18.3k
1726
    external_constructor<value_t::string>::construct(j, s);
18.3k
1727
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEA6_cLi0EEEvRT_RKT0_
1
1725
{
1
1726
    external_constructor<value_t::string>::construct(j, s);
1
1727
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEPKcLi0EEEvRT_RKT0_
10
1725
{
10
1726
    external_constructor<value_t::string>::construct(j, s);
10
1727
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEA474_cLi0EEEvRT_RKT0_
58
1725
{
58
1726
    external_constructor<value_t::string>::construct(j, s);
58
1727
}
1728
1729
template<typename BasicJsonType>
1730
void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
144
1731
{
144
1732
    external_constructor<value_t::string>::construct(j, std::move(s));
144
1733
}
1734
1735
template<typename BasicJsonType, typename FloatType,
1736
         enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
1737
void to_json(BasicJsonType& j, FloatType val) noexcept
16.8k
1738
{
16.8k
1739
    external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
16.8k
1740
}
1741
1742
template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
1743
         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
1744
void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
22.6k
1745
{
22.6k
1746
    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
22.6k
1747
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEmLi0EEEvRT_T0_
22.6k
1745
{
22.6k
1746
    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
22.6k
1747
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEjLi0EEEvRT_T0_
48
1745
{
48
1746
    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
48
1747
}
1748
1749
template<typename BasicJsonType, typename CompatibleNumberIntegerType,
1750
         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
1751
void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
2.69k
1752
{
2.69k
1753
    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
2.69k
1754
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEiLi0EEEvRT_T0_
1
1752
{
1
1753
    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
1
1754
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEElLi0EEEvRT_T0_
2.69k
1752
{
2.69k
1753
    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
2.69k
1754
}
1755
1756
template<typename BasicJsonType, typename EnumType,
1757
         enable_if_t<std::is_enum<EnumType>::value, int> = 0>
1758
void to_json(BasicJsonType& j, EnumType e) noexcept
1759
{
1760
    using underlying_type = typename std::underlying_type<EnumType>::type;
1761
    external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
1762
}
1763
1764
template<typename BasicJsonType>
1765
void to_json(BasicJsonType& j, const std::vector<bool>& e)
1766
{
1767
    external_constructor<value_t::array>::construct(j, e);
1768
}
1769
1770
template <typename BasicJsonType, typename CompatibleArrayType,
1771
          enable_if_t<is_compatible_array_type<BasicJsonType,
1772
                      CompatibleArrayType>::value and
1773
                      not is_compatible_object_type<
1774
                          BasicJsonType, CompatibleArrayType>::value and
1775
                      not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
1776
                      not is_basic_json<CompatibleArrayType>::value,
1777
                      int> = 0>
1778
void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
1779
{
1780
    external_constructor<value_t::array>::construct(j, arr);
1781
}
1782
1783
template<typename BasicJsonType, typename T,
1784
         enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
1785
void to_json(BasicJsonType& j, const std::valarray<T>& arr)
1786
{
1787
    external_constructor<value_t::array>::construct(j, std::move(arr));
1788
}
1789
1790
template<typename BasicJsonType>
1791
void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
1792
{
1793
    external_constructor<value_t::array>::construct(j, std::move(arr));
1794
}
1795
1796
template<typename BasicJsonType, typename CompatibleObjectType,
1797
         enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0>
1798
void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
1799
{
1800
    external_constructor<value_t::object>::construct(j, obj);
1801
}
1802
1803
template<typename BasicJsonType>
1804
void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
1805
{
1806
    external_constructor<value_t::object>::construct(j, std::move(obj));
1807
}
1808
1809
template <
1810
    typename BasicJsonType, typename T, std::size_t N,
1811
    enable_if_t<not std::is_constructible<typename BasicJsonType::string_t,
1812
                const T (&)[N]>::value,
1813
                int> = 0 >
1814
void to_json(BasicJsonType& j, const T (&arr)[N])
1815
{
1816
    external_constructor<value_t::array>::construct(j, arr);
1817
}
1818
1819
template<typename BasicJsonType, typename... Args>
1820
void to_json(BasicJsonType& j, const std::pair<Args...>& p)
1821
{
1822
    j = {p.first, p.second};
1823
}
1824
1825
// for https://github.com/nlohmann/json/pull/1134
1826
template<typename BasicJsonType, typename T,
1827
         enable_if_t<std::is_same<T, typename iteration_proxy<typename BasicJsonType::iterator>::iteration_proxy_internal>::value, int> = 0>
1828
void to_json(BasicJsonType& j, T b) noexcept
1829
{
1830
    j = {{b.key(), b.value()}};
1831
}
1832
1833
template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
1834
void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...>)
1835
{
1836
    j = {std::get<Idx>(t)...};
1837
}
1838
1839
template<typename BasicJsonType, typename... Args>
1840
void to_json(BasicJsonType& j, const std::tuple<Args...>& t)
1841
{
1842
    to_json_tuple_impl(j, t, index_sequence_for<Args...> {});
1843
}
1844
1845
struct to_json_fn
1846
{
1847
    template<typename BasicJsonType, typename T>
1848
    auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
1849
    -> decltype(to_json(j, std::forward<T>(val)), void())
60.9k
1850
    {
60.9k
1851
        return to_json(j, std::forward<T>(val));
60.9k
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEKSB_EEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
16
1850
    {
16
1851
        return to_json(j, std::forward<T>(val));
16
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERA474_KcEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSH_
58
1850
    {
58
1851
        return to_json(j, std::forward<T>(val));
58
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEESB_EEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
144
1850
    {
144
1851
        return to_json(j, std::forward<T>(val));
144
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERjEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
48
1850
    {
48
1851
        return to_json(j, std::forward<T>(val));
48
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERKPKcEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSI_
10
1850
    {
10
1851
        return to_json(j, std::forward<T>(val));
10
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEbEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
1
1850
    {
1
1851
        return to_json(j, std::forward<T>(val));
1
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEdEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
1
1850
    {
1
1851
        return to_json(j, std::forward<T>(val));
1
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERA6_KcEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSH_
1
1850
    {
1
1851
        return to_json(j, std::forward<T>(val));
1
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEiEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
1
1850
    {
1
1851
        return to_json(j, std::forward<T>(val));
1
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERmEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
22.6k
1850
    {
22.6k
1851
        return to_json(j, std::forward<T>(val));
22.6k
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERlEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
2.69k
1850
    {
2.69k
1851
        return to_json(j, std::forward<T>(val));
2.69k
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERbEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
179
1850
    {
179
1851
        return to_json(j, std::forward<T>(val));
179
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERdEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
16.8k
1850
    {
16.8k
1851
        return to_json(j, std::forward<T>(val));
16.8k
1852
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERSB_EEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
18.3k
1850
    {
18.3k
1851
        return to_json(j, std::forward<T>(val));
18.3k
1852
    }
1853
};
1854
}
1855
1856
/// namespace to hold default `to_json` function
1857
namespace
1858
{
1859
constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;
1860
}
1861
}
1862
1863
// #include <nlohmann/detail/input/input_adapters.hpp>
1864
1865
1866
#include <cassert> // assert
1867
#include <cstddef> // size_t
1868
#include <cstring> // strlen
1869
#include <istream> // istream
1870
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
1871
#include <memory> // shared_ptr, make_shared, addressof
1872
#include <numeric> // accumulate
1873
#include <string> // string, char_traits
1874
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
1875
#include <utility> // pair, declval
1876
1877
// #include <nlohmann/detail/macro_scope.hpp>
1878
1879
1880
namespace nlohmann
1881
{
1882
namespace detail
1883
{
1884
/// the supported input formats
1885
enum class input_format_t { json, cbor, msgpack, ubjson };
1886
1887
////////////////////
1888
// input adapters //
1889
////////////////////
1890
1891
/*!
1892
@brief abstract input adapter interface
1893
1894
Produces a stream of std::char_traits<char>::int_type characters from a
1895
std::istream, a buffer, or some other input type. Accepts the return of
1896
exactly one non-EOF character for future input. The int_type characters
1897
returned consist of all valid char values as positive values (typically
1898
unsigned char), plus an EOF value outside that range, specified by the value
1899
of the function std::char_traits<char>::eof(). This value is typically -1, but
1900
could be any arbitrary value which is not a valid char value.
1901
*/
1902
struct input_adapter_protocol
1903
{
1904
    /// get a character [0,255] or std::char_traits<char>::eof().
1905
    virtual std::char_traits<char>::int_type get_character() = 0;
258
1906
    virtual ~input_adapter_protocol() = default;
1907
};
1908
1909
/// a type to simplify interfaces
1910
using input_adapter_t = std::shared_ptr<input_adapter_protocol>;
1911
1912
/*!
1913
Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
1914
beginning of input. Does not support changing the underlying std::streambuf
1915
in mid-input. Maintains underlying std::istream and std::streambuf to support
1916
subsequent use of standard std::istream operations to process any input
1917
characters following those used in parsing the JSON input.  Clears the
1918
std::istream flags; any input errors (e.g., EOF) will be detected by the first
1919
subsequent call for input from the std::istream.
1920
*/
1921
class input_stream_adapter : public input_adapter_protocol
1922
{
1923
  public:
1924
    ~input_stream_adapter() override
57
1925
    {
57
1926
        // clear stream flags; we use underlying streambuf I/O, do not
57
1927
        // maintain ifstream flags
57
1928
        is.clear();
57
1929
    }
1930
1931
    explicit input_stream_adapter(std::istream& i)
1932
        : is(i), sb(*i.rdbuf())
57
1933
    {}
1934
1935
    // delete because of pointer members
1936
    input_stream_adapter(const input_stream_adapter&) = delete;
1937
    input_stream_adapter& operator=(input_stream_adapter&) = delete;
1938
1939
    // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
1940
    // ensure that std::char_traits<char>::eof() and the character 0xFF do not
1941
    // end up as the same value, eg. 0xFFFFFFFF.
1942
    std::char_traits<char>::int_type get_character() override
117k
1943
    {
117k
1944
        return sb.sbumpc();
117k
1945
    }
1946
1947
  private:
1948
    /// the associated input stream
1949
    std::istream& is;
1950
    std::streambuf& sb;
1951
};
1952
1953
/// input adapter for buffer input
1954
class input_buffer_adapter : public input_adapter_protocol
1955
{
1956
  public:
1957
    input_buffer_adapter(const char* b, const std::size_t l)
1958
        : cursor(b), limit(b + l)
201
1959
    {}
1960
1961
    // delete because of pointer members
1962
    input_buffer_adapter(const input_buffer_adapter&) = delete;
1963
    input_buffer_adapter& operator=(input_buffer_adapter&) = delete;
1964
1965
    std::char_traits<char>::int_type get_character() noexcept override
1.21M
1966
    {
1.21M
1967
        if (JSON_LIKELY(cursor < limit))
1.21M
1968
        {
1.21M
1969
            return std::char_traits<char>::to_int_type(*(cursor++));
1.21M
1970
        }
1.21M
1971
27
1972
        return std::char_traits<char>::eof();
1.21M
1973
    }
1974
1975
  private:
1976
    /// pointer to the current character
1977
    const char* cursor;
1978
    /// pointer past the last character
1979
    const char* const limit;
1980
};
1981
1982
template<typename WideStringType>
1983
class wide_string_input_adapter : public input_adapter_protocol
1984
{
1985
  public:
1986
    explicit wide_string_input_adapter(const WideStringType& w) : str(w) {}
1987
1988
    std::char_traits<char>::int_type get_character() noexcept override
0
1989
    {
0
1990
        // check if buffer needs to be filled
0
1991
        if (utf8_bytes_index == utf8_bytes_filled)
0
1992
        {
0
1993
            if (sizeof(typename WideStringType::value_type) == 2)
0
1994
            {
0
1995
                fill_buffer_utf16();
0
1996
            }
0
1997
            else
0
1998
            {
0
1999
                fill_buffer_utf32();
0
2000
            }
0
2001
0
2002
            assert(utf8_bytes_filled > 0);
0
2003
            assert(utf8_bytes_index == 0);
0
2004
        }
0
2005
0
2006
        // use buffer
0
2007
        assert(utf8_bytes_filled > 0);
0
2008
        assert(utf8_bytes_index < utf8_bytes_filled);
0
2009
        return utf8_bytes[utf8_bytes_index++];
0
2010
    }
_ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDiSt11char_traitsIDiESaIDiEEEE13get_characterEv
0
1989
    {
0
1990
        // check if buffer needs to be filled
0
1991
        if (utf8_bytes_index == utf8_bytes_filled)
0
1992
        {
0
1993
            if (sizeof(typename WideStringType::value_type) == 2)
0
1994
            {
0
1995
                fill_buffer_utf16();
0
1996
            }
0
1997
            else
0
1998
            {
0
1999
                fill_buffer_utf32();
0
2000
            }
0
2001
0
2002
            assert(utf8_bytes_filled > 0);
0
2003
            assert(utf8_bytes_index == 0);
0
2004
        }
0
2005
0
2006
        // use buffer
0
2007
        assert(utf8_bytes_filled > 0);
0
2008
        assert(utf8_bytes_index < utf8_bytes_filled);
0
2009
        return utf8_bytes[utf8_bytes_index++];
0
2010
    }
_ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEEEE13get_characterEv
0
1989
    {
0
1990
        // check if buffer needs to be filled
0
1991
        if (utf8_bytes_index == utf8_bytes_filled)
0
1992
        {
0
1993
            if (sizeof(typename WideStringType::value_type) == 2)
0
1994
            {
0
1995
                fill_buffer_utf16();
0
1996
            }
0
1997
            else
0
1998
            {
0
1999
                fill_buffer_utf32();
0
2000
            }
0
2001
0
2002
            assert(utf8_bytes_filled > 0);
0
2003
            assert(utf8_bytes_index == 0);
0
2004
        }
0
2005
0
2006
        // use buffer
0
2007
        assert(utf8_bytes_filled > 0);
0
2008
        assert(utf8_bytes_index < utf8_bytes_filled);
0
2009
        return utf8_bytes[utf8_bytes_index++];
0
2010
    }
_ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDsSt11char_traitsIDsESaIDsEEEE13get_characterEv
0
1989
    {
0
1990
        // check if buffer needs to be filled
0
1991
        if (utf8_bytes_index == utf8_bytes_filled)
0
1992
        {
0
1993
            if (sizeof(typename WideStringType::value_type) == 2)
0
1994
            {
0
1995
                fill_buffer_utf16();
0
1996
            }
0
1997
            else
0
1998
            {
0
1999
                fill_buffer_utf32();
0
2000
            }
0
2001
0
2002
            assert(utf8_bytes_filled > 0);
0
2003
            assert(utf8_bytes_index == 0);
0
2004
        }
0
2005
0
2006
        // use buffer
0
2007
        assert(utf8_bytes_filled > 0);
0
2008
        assert(utf8_bytes_index < utf8_bytes_filled);
0
2009
        return utf8_bytes[utf8_bytes_index++];
0
2010
    }
2011
2012
  private:
2013
    void fill_buffer_utf16()
0
2014
    {
0
2015
        utf8_bytes_index = 0;
0
2016
0
2017
        if (current_wchar == str.size())
0
2018
        {
0
2019
            utf8_bytes[0] = std::char_traits<char>::eof();
0
2020
            utf8_bytes_filled = 1;
0
2021
        }
0
2022
        else
0
2023
        {
0
2024
            // get the current character
0
2025
            const int wc = static_cast<int>(str[current_wchar++]);
0
2026
0
2027
            // UTF-16 to UTF-8 encoding
0
2028
            if (wc < 0x80)
0
2029
            {
0
2030
                utf8_bytes[0] = wc;
0
2031
                utf8_bytes_filled = 1;
0
2032
            }
0
2033
            else if (wc <= 0x7FF)
0
2034
            {
0
2035
                utf8_bytes[0] = 0xC0 | ((wc >> 6));
0
2036
                utf8_bytes[1] = 0x80 | (wc & 0x3F);
0
2037
                utf8_bytes_filled = 2;
0
2038
            }
0
2039
            else if (0xD800 > wc or wc >= 0xE000)
0
2040
            {
0
2041
                utf8_bytes[0] = 0xE0 | ((wc >> 12));
0
2042
                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
0
2043
                utf8_bytes[2] = 0x80 | (wc & 0x3F);
0
2044
                utf8_bytes_filled = 3;
0
2045
            }
0
2046
            else
0
2047
            {
0
2048
                if (current_wchar < str.size())
0
2049
                {
0
2050
                    const int wc2 = static_cast<int>(str[current_wchar++]);
0
2051
                    const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF));
0
2052
                    utf8_bytes[0] = 0xf0 | (charcode >> 18);
0
2053
                    utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F);
0
2054
                    utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F);
0
2055
                    utf8_bytes[3] = 0x80 | (charcode & 0x3F);
0
2056
                    utf8_bytes_filled = 4;
0
2057
                }
0
2058
                else
0
2059
                {
0
2060
                    // unknown character
0
2061
                    ++current_wchar;
0
2062
                    utf8_bytes[0] = wc;
0
2063
                    utf8_bytes_filled = 1;
0
2064
                }
0
2065
            }
0
2066
        }
0
2067
    }
_ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDsSt11char_traitsIDsESaIDsEEEE17fill_buffer_utf16Ev
0
2014
    {
0
2015
        utf8_bytes_index = 0;
0
2016
0
2017
        if (current_wchar == str.size())
0
2018
        {
0
2019
            utf8_bytes[0] = std::char_traits<char>::eof();
0
2020
            utf8_bytes_filled = 1;
0
2021
        }
0
2022
        else
0
2023
        {
0
2024
            // get the current character
0
2025
            const int wc = static_cast<int>(str[current_wchar++]);
0
2026
0
2027
            // UTF-16 to UTF-8 encoding
0
2028
            if (wc < 0x80)
0
2029
            {
0
2030
                utf8_bytes[0] = wc;
0
2031
                utf8_bytes_filled = 1;
0
2032
            }
0
2033
            else if (wc <= 0x7FF)
0
2034
            {
0
2035
                utf8_bytes[0] = 0xC0 | ((wc >> 6));
0
2036
                utf8_bytes[1] = 0x80 | (wc & 0x3F);
0
2037
                utf8_bytes_filled = 2;
0
2038
            }
0
2039
            else if (0xD800 > wc or wc >= 0xE000)
0
2040
            {
0
2041
                utf8_bytes[0] = 0xE0 | ((wc >> 12));
0
2042
                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
0
2043
                utf8_bytes[2] = 0x80 | (wc & 0x3F);
0
2044
                utf8_bytes_filled = 3;
0
2045
            }
0
2046
            else
0
2047
            {
0
2048
                if (current_wchar < str.size())
0
2049
                {
0
2050
                    const int wc2 = static_cast<int>(str[current_wchar++]);
0
2051
                    const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF));
0
2052
                    utf8_bytes[0] = 0xf0 | (charcode >> 18);
0
2053
                    utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F);
0
2054
                    utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F);
0
2055
                    utf8_bytes[3] = 0x80 | (charcode & 0x3F);
0
2056
                    utf8_bytes_filled = 4;
0
2057
                }
0
2058
                else
0
2059
                {
0
2060
                    // unknown character
0
2061
                    ++current_wchar;
0
2062
                    utf8_bytes[0] = wc;
0
2063
                    utf8_bytes_filled = 1;
0
2064
                }
0
2065
            }
0
2066
        }
0
2067
    }
_ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDiSt11char_traitsIDiESaIDiEEEE17fill_buffer_utf16Ev
0
2014
    {
0
2015
        utf8_bytes_index = 0;
0
2016
0
2017
        if (current_wchar == str.size())
0
2018
        {
0
2019
            utf8_bytes[0] = std::char_traits<char>::eof();
0
2020
            utf8_bytes_filled = 1;
0
2021
        }
0
2022
        else
0
2023
        {
0
2024
            // get the current character
0
2025
            const int wc = static_cast<int>(str[current_wchar++]);
0
2026
0
2027
            // UTF-16 to UTF-8 encoding
0
2028
            if (wc < 0x80)
0
2029
            {
0
2030
                utf8_bytes[0] = wc;
0
2031
                utf8_bytes_filled = 1;
0
2032
            }
0
2033
            else if (wc <= 0x7FF)
0
2034
            {
0
2035
                utf8_bytes[0] = 0xC0 | ((wc >> 6));
0
2036
                utf8_bytes[1] = 0x80 | (wc & 0x3F);
0
2037
                utf8_bytes_filled = 2;
0
2038
            }
0
2039
            else if (0xD800 > wc or wc >= 0xE000)
0
2040
            {
0
2041
                utf8_bytes[0] = 0xE0 | ((wc >> 12));
0
2042
                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
0
2043
                utf8_bytes[2] = 0x80 | (wc & 0x3F);
0
2044
                utf8_bytes_filled = 3;
0
2045
            }
0
2046
            else
0
2047
            {
0
2048
                if (current_wchar < str.size())
0
2049
                {
0
2050
                    const int wc2 = static_cast<int>(str[current_wchar++]);
0
2051
                    const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF));
0
2052
                    utf8_bytes[0] = 0xf0 | (charcode >> 18);
0
2053
                    utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F);
0
2054
                    utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F);
0
2055
                    utf8_bytes[3] = 0x80 | (charcode & 0x3F);
0
2056
                    utf8_bytes_filled = 4;
0
2057
                }
0
2058
                else
0
2059
                {
0
2060
                    // unknown character
0
2061
                    ++current_wchar;
0
2062
                    utf8_bytes[0] = wc;
0
2063
                    utf8_bytes_filled = 1;
0
2064
                }
0
2065
            }
0
2066
        }
0
2067
    }
_ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEEEE17fill_buffer_utf16Ev
0
2014
    {
0
2015
        utf8_bytes_index = 0;
0
2016
0
2017
        if (current_wchar == str.size())
0
2018
        {
0
2019
            utf8_bytes[0] = std::char_traits<char>::eof();
0
2020
            utf8_bytes_filled = 1;
0
2021
        }
0
2022
        else
0
2023
        {
0
2024
            // get the current character
0
2025
            const int wc = static_cast<int>(str[current_wchar++]);
0
2026
0
2027
            // UTF-16 to UTF-8 encoding
0
2028
            if (wc < 0x80)
0
2029
            {
0
2030
                utf8_bytes[0] = wc;
0
2031
                utf8_bytes_filled = 1;
0
2032
            }
0
2033
            else if (wc <= 0x7FF)
0
2034
            {
0
2035
                utf8_bytes[0] = 0xC0 | ((wc >> 6));
0
2036
                utf8_bytes[1] = 0x80 | (wc & 0x3F);
0
2037
                utf8_bytes_filled = 2;
0
2038
            }
0
2039
            else if (0xD800 > wc or wc >= 0xE000)
0
2040
            {
0
2041
                utf8_bytes[0] = 0xE0 | ((wc >> 12));
0
2042
                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
0
2043
                utf8_bytes[2] = 0x80 | (wc & 0x3F);
0
2044
                utf8_bytes_filled = 3;
0
2045
            }
0
2046
            else
0
2047
            {
0
2048
                if (current_wchar < str.size())
0
2049
                {
0
2050
                    const int wc2 = static_cast<int>(str[current_wchar++]);
0
2051
                    const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF));
0
2052
                    utf8_bytes[0] = 0xf0 | (charcode >> 18);
0
2053
                    utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F);
0
2054
                    utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F);
0
2055
                    utf8_bytes[3] = 0x80 | (charcode & 0x3F);
0
2056
                    utf8_bytes_filled = 4;
0
2057
                }
0
2058
                else
0
2059
                {
0
2060
                    // unknown character
0
2061
                    ++current_wchar;
0
2062
                    utf8_bytes[0] = wc;
0
2063
                    utf8_bytes_filled = 1;
0
2064
                }
0
2065
            }
0
2066
        }
0
2067
    }
2068
2069
    void fill_buffer_utf32()
0
2070
    {
0
2071
        utf8_bytes_index = 0;
0
2072
0
2073
        if (current_wchar == str.size())
0
2074
        {
0
2075
            utf8_bytes[0] = std::char_traits<char>::eof();
0
2076
            utf8_bytes_filled = 1;
0
2077
        }
0
2078
        else
0
2079
        {
0
2080
            // get the current character
0
2081
            const int wc = static_cast<int>(str[current_wchar++]);
0
2082
0
2083
            // UTF-32 to UTF-8 encoding
0
2084
            if (wc < 0x80)
0
2085
            {
0
2086
                utf8_bytes[0] = wc;
0
2087
                utf8_bytes_filled = 1;
0
2088
            }
0
2089
            else if (wc <= 0x7FF)
0
2090
            {
0
2091
                utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);
0
2092
                utf8_bytes[1] = 0x80 | (wc & 0x3F);
0
2093
                utf8_bytes_filled = 2;
0
2094
            }
0
2095
            else if (wc <= 0xFFFF)
0
2096
            {
0
2097
                utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);
0
2098
                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
0
2099
                utf8_bytes[2] = 0x80 | (wc & 0x3F);
0
2100
                utf8_bytes_filled = 3;
0
2101
            }
0
2102
            else if (wc <= 0x10FFFF)
0
2103
            {
0
2104
                utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07);
0
2105
                utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);
0
2106
                utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);
0
2107
                utf8_bytes[3] = 0x80 | (wc & 0x3F);
0
2108
                utf8_bytes_filled = 4;
0
2109
            }
0
2110
            else
0
2111
            {
0
2112
                // unknown character
0
2113
                utf8_bytes[0] = wc;
0
2114
                utf8_bytes_filled = 1;
0
2115
            }
0
2116
        }
0
2117
    }
_ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDsSt11char_traitsIDsESaIDsEEEE17fill_buffer_utf32Ev
0
2070
    {
0
2071
        utf8_bytes_index = 0;
0
2072
0
2073
        if (current_wchar == str.size())
0
2074
        {
0
2075
            utf8_bytes[0] = std::char_traits<char>::eof();
0
2076
            utf8_bytes_filled = 1;
0
2077
        }
0
2078
        else
0
2079
        {
0
2080
            // get the current character
0
2081
            const int wc = static_cast<int>(str[current_wchar++]);
0
2082
0
2083
            // UTF-32 to UTF-8 encoding
0
2084
            if (wc < 0x80)
0
2085
            {
0
2086
                utf8_bytes[0] = wc;
0
2087
                utf8_bytes_filled = 1;
0
2088
            }
0
2089
            else if (wc <= 0x7FF)
0
2090
            {
0
2091
                utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);
0
2092
                utf8_bytes[1] = 0x80 | (wc & 0x3F);
0
2093
                utf8_bytes_filled = 2;
0
2094
            }
0
2095
            else if (wc <= 0xFFFF)
0
2096
            {
0
2097
                utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);
0
2098
                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
0
2099
                utf8_bytes[2] = 0x80 | (wc & 0x3F);
0
2100
                utf8_bytes_filled = 3;
0
2101
            }
0
2102
            else if (wc <= 0x10FFFF)
0
2103
            {
0
2104
                utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07);
0
2105
                utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);
0
2106
                utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);
0
2107
                utf8_bytes[3] = 0x80 | (wc & 0x3F);
0
2108
                utf8_bytes_filled = 4;
0
2109
            }
0
2110
            else
0
2111
            {
0
2112
                // unknown character
0
2113
                utf8_bytes[0] = wc;
0
2114
                utf8_bytes_filled = 1;
0
2115
            }
0
2116
        }
0
2117
    }
_ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEEEE17fill_buffer_utf32Ev
0
2070
    {
0
2071
        utf8_bytes_index = 0;
0
2072
0
2073
        if (current_wchar == str.size())
0
2074
        {
0
2075
            utf8_bytes[0] = std::char_traits<char>::eof();
0
2076
            utf8_bytes_filled = 1;
0
2077
        }
0
2078
        else
0
2079
        {
0
2080
            // get the current character
0
2081
            const int wc = static_cast<int>(str[current_wchar++]);
0
2082
0
2083
            // UTF-32 to UTF-8 encoding
0
2084
            if (wc < 0x80)
0
2085
            {
0
2086
                utf8_bytes[0] = wc;
0
2087
                utf8_bytes_filled = 1;
0
2088
            }
0
2089
            else if (wc <= 0x7FF)
0
2090
            {
0
2091
                utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);
0
2092
                utf8_bytes[1] = 0x80 | (wc & 0x3F);
0
2093
                utf8_bytes_filled = 2;
0
2094
            }
0
2095
            else if (wc <= 0xFFFF)
0
2096
            {
0
2097
                utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);
0
2098
                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
0
2099
                utf8_bytes[2] = 0x80 | (wc & 0x3F);
0
2100
                utf8_bytes_filled = 3;
0
2101
            }
0
2102
            else if (wc <= 0x10FFFF)
0
2103
            {
0
2104
                utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07);
0
2105
                utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);
0
2106
                utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);
0
2107
                utf8_bytes[3] = 0x80 | (wc & 0x3F);
0
2108
                utf8_bytes_filled = 4;
0
2109
            }
0
2110
            else
0
2111
            {
0
2112
                // unknown character
0
2113
                utf8_bytes[0] = wc;
0
2114
                utf8_bytes_filled = 1;
0
2115
            }
0
2116
        }
0
2117
    }
_ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDiSt11char_traitsIDiESaIDiEEEE17fill_buffer_utf32Ev
0
2070
    {
0
2071
        utf8_bytes_index = 0;
0
2072
0
2073
        if (current_wchar == str.size())
0
2074
        {
0
2075
            utf8_bytes[0] = std::char_traits<char>::eof();
0
2076
            utf8_bytes_filled = 1;
0
2077
        }
0
2078
        else
0
2079
        {
0
2080
            // get the current character
0
2081
            const int wc = static_cast<int>(str[current_wchar++]);
0
2082
0
2083
            // UTF-32 to UTF-8 encoding
0
2084
            if (wc < 0x80)
0
2085
            {
0
2086
                utf8_bytes[0] = wc;
0
2087
                utf8_bytes_filled = 1;
0
2088
            }
0
2089
            else if (wc <= 0x7FF)
0
2090
            {
0
2091
                utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);
0
2092
                utf8_bytes[1] = 0x80 | (wc & 0x3F);
0
2093
                utf8_bytes_filled = 2;
0
2094
            }
0
2095
            else if (wc <= 0xFFFF)
0
2096
            {
0
2097
                utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);
0
2098
                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
0
2099
                utf8_bytes[2] = 0x80 | (wc & 0x3F);
0
2100
                utf8_bytes_filled = 3;
0
2101
            }
0
2102
            else if (wc <= 0x10FFFF)
0
2103
            {
0
2104
                utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07);
0
2105
                utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);
0
2106
                utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);
0
2107
                utf8_bytes[3] = 0x80 | (wc & 0x3F);
0
2108
                utf8_bytes_filled = 4;
0
2109
            }
0
2110
            else
0
2111
            {
0
2112
                // unknown character
0
2113
                utf8_bytes[0] = wc;
0
2114
                utf8_bytes_filled = 1;
0
2115
            }
0
2116
        }
0
2117
    }
2118
2119
  private:
2120
    /// the wstring to process
2121
    const WideStringType& str;
2122
2123
    /// index of the current wchar in str
2124
    std::size_t current_wchar = 0;
2125
2126
    /// a buffer for UTF-8 bytes
2127
    std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
2128
2129
    /// index to the utf8_codes array for the next valid byte
2130
    std::size_t utf8_bytes_index = 0;
2131
    /// number of valid bytes in the utf8_codes array
2132
    std::size_t utf8_bytes_filled = 0;
2133
};
2134
2135
class input_adapter
2136
{
2137
  public:
2138
    // native support
2139
2140
    /// input adapter for input stream
2141
    input_adapter(std::istream& i)
57
2142
        : ia(std::make_shared<input_stream_adapter>(i)) {}
2143
2144
    /// input adapter for input stream
2145
    input_adapter(std::istream&& i)
0
2146
        : ia(std::make_shared<input_stream_adapter>(i)) {}
2147
2148
    input_adapter(const std::wstring& ws)
0
2149
        : ia(std::make_shared<wide_string_input_adapter<std::wstring>>(ws)) {}
2150
2151
    input_adapter(const std::u16string& ws)
0
2152
        : ia(std::make_shared<wide_string_input_adapter<std::u16string>>(ws)) {}
2153
2154
    input_adapter(const std::u32string& ws)
0
2155
        : ia(std::make_shared<wide_string_input_adapter<std::u32string>>(ws)) {}
2156
2157
    /// input adapter for buffer
2158
    template<typename CharT,
2159
             typename std::enable_if<
2160
                 std::is_pointer<CharT>::value and
2161
                 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
2162
                 sizeof(typename std::remove_pointer<CharT>::type) == 1,
2163
                 int>::type = 0>
2164
    input_adapter(CharT b, std::size_t l)
2165
        : ia(std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(b), l)) {}
2166
2167
    // derived support
2168
2169
    /// input adapter for string literal
2170
    template<typename CharT,
2171
             typename std::enable_if<
2172
                 std::is_pointer<CharT>::value and
2173
                 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
2174
                 sizeof(typename std::remove_pointer<CharT>::type) == 1,
2175
                 int>::type = 0>
2176
    input_adapter(CharT b)
2177
        : input_adapter(reinterpret_cast<const char*>(b),
2178
                        std::strlen(reinterpret_cast<const char*>(b))) {}
2179
2180
    /// input adapter for iterator range with contiguous storage
2181
    template<class IteratorType,
2182
             typename std::enable_if<
2183
                 std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
2184
                 int>::type = 0>
2185
    input_adapter(IteratorType first, IteratorType last)
201
2186
    {
201
2187
#ifndef NDEBUG
201
2188
        // assertion to check that the iterator range is indeed contiguous,
201
2189
        // see http://stackoverflow.com/a/35008842/266378 for more discussion
201
2190
        const auto is_contiguous = std::accumulate(
201
2191
                                       first, last, std::pair<bool, int>(true, 0),
201
2192
                                       [&first](std::pair<bool, int> res, decltype(*first) val)
1.21M
2193
        {
1.21M
2194
            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
1.21M
2195
            return res;
1.21M
2196
        }).first;
_ZZN8nlohmann6detail13input_adapterC1IN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEELi0EEET_SE_ENKUlSt4pairIbiERS5_E_clESG_SH_
12.2k
2193
        {
12.2k
2194
            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
12.2k
2195
            return res;
12.2k
2196
        }).first;
_ZZN8nlohmann6detail13input_adapterC1IPKcLi0EEET_S5_ENKUlSt4pairIbiERS3_E_clES7_S8_
1.19M
2193
        {
1.19M
2194
            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
1.19M
2195
            return res;
1.19M
2196
        }).first;
201
2197
        assert(is_contiguous);
201
2198
#endif
201
2199
201
2200
        // assertion to check that each element is 1 byte long
201
2201
        static_assert(
201
2202
            sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
201
2203
            "each element in the iterator range must have the size of 1 byte");
201
2204
201
2205
        const auto len = static_cast<size_t>(std::distance(first, last));
201
2206
        if (JSON_LIKELY(len > 0))
201
2207
        {
201
2208
            // there is at least one element: use the address of first
201
2209
            ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);
201
2210
        }
201
2211
        else
0
2212
        {
0
2213
            // the address of first cannot be used: use nullptr
0
2214
            ia = std::make_shared<input_buffer_adapter>(nullptr, len);
0
2215
        }
201
2216
    }
_ZN8nlohmann6detail13input_adapterC2IN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEELi0EEET_SE_
27
2186
    {
27
2187
#ifndef NDEBUG
27
2188
        // assertion to check that the iterator range is indeed contiguous,
27
2189
        // see http://stackoverflow.com/a/35008842/266378 for more discussion
27
2190
        const auto is_contiguous = std::accumulate(
27
2191
                                       first, last, std::pair<bool, int>(true, 0),
27
2192
                                       [&first](std::pair<bool, int> res, decltype(*first) val)
27
2193
        {
27
2194
            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
27
2195
            return res;
27
2196
        }).first;
27
2197
        assert(is_contiguous);
27
2198
#endif
27
2199
27
2200
        // assertion to check that each element is 1 byte long
27
2201
        static_assert(
27
2202
            sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
27
2203
            "each element in the iterator range must have the size of 1 byte");
27
2204
27
2205
        const auto len = static_cast<size_t>(std::distance(first, last));
27
2206
        if (JSON_LIKELY(len > 0))
27
2207
        {
27
2208
            // there is at least one element: use the address of first
27
2209
            ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);
27
2210
        }
27
2211
        else
0
2212
        {
0
2213
            // the address of first cannot be used: use nullptr
0
2214
            ia = std::make_shared<input_buffer_adapter>(nullptr, len);
0
2215
        }
27
2216
    }
_ZN8nlohmann6detail13input_adapterC2IPKcLi0EEET_S5_
174
2186
    {
174
2187
#ifndef NDEBUG
174
2188
        // assertion to check that the iterator range is indeed contiguous,
174
2189
        // see http://stackoverflow.com/a/35008842/266378 for more discussion
174
2190
        const auto is_contiguous = std::accumulate(
174
2191
                                       first, last, std::pair<bool, int>(true, 0),
174
2192
                                       [&first](std::pair<bool, int> res, decltype(*first) val)
174
2193
        {
174
2194
            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
174
2195
            return res;
174
2196
        }).first;
174
2197
        assert(is_contiguous);
174
2198
#endif
174
2199
174
2200
        // assertion to check that each element is 1 byte long
174
2201
        static_assert(
174
2202
            sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
174
2203
            "each element in the iterator range must have the size of 1 byte");
174
2204
174
2205
        const auto len = static_cast<size_t>(std::distance(first, last));
174
2206
        if (JSON_LIKELY(len > 0))
174
2207
        {
174
2208
            // there is at least one element: use the address of first
174
2209
            ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);
174
2210
        }
174
2211
        else
0
2212
        {
0
2213
            // the address of first cannot be used: use nullptr
0
2214
            ia = std::make_shared<input_buffer_adapter>(nullptr, len);
0
2215
        }
174
2216
    }
2217
2218
    /// input adapter for array
2219
    template<class T, std::size_t N>
2220
    input_adapter(T (&array)[N])
174
2221
        : input_adapter(std::begin(array), std::end(array)) {}
_ZN8nlohmann6detail13input_adapterC2IKcLm117EEERAT0__T_
58
2221
        : input_adapter(std::begin(array), std::end(array)) {}
_ZN8nlohmann6detail13input_adapterC2IKcLm10282EEERAT0__T_
58
2221
        : input_adapter(std::begin(array), std::end(array)) {}
_ZN8nlohmann6detail13input_adapterC2IKcLm10259EEERAT0__T_
58
2221
        : input_adapter(std::begin(array), std::end(array)) {}
2222
2223
    /// input adapter for contiguous container
2224
    template<class ContiguousContainer, typename
2225
             std::enable_if<not std::is_pointer<ContiguousContainer>::value and
2226
                            std::is_base_of<std::random_access_iterator_tag, typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
2227
                            int>::type = 0>
2228
    input_adapter(const ContiguousContainer& c)
27
2229
        : input_adapter(std::begin(c), std::end(c)) {}
2230
2231
    operator input_adapter_t()
258
2232
    {
258
2233
        return ia;
258
2234
    }
2235
2236
  private:
2237
    /// the actual adapter
2238
    input_adapter_t ia = nullptr;
2239
};
2240
}
2241
}
2242
2243
// #include <nlohmann/detail/input/lexer.hpp>
2244
2245
2246
#include <clocale> // localeconv
2247
#include <cstddef> // size_t
2248
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
2249
#include <cstdio> // snprintf
2250
#include <initializer_list> // initializer_list
2251
#include <string> // char_traits, string
2252
#include <vector> // vector
2253
2254
// #include <nlohmann/detail/macro_scope.hpp>
2255
2256
// #include <nlohmann/detail/input/input_adapters.hpp>
2257
2258
2259
namespace nlohmann
2260
{
2261
namespace detail
2262
{
2263
///////////
2264
// lexer //
2265
///////////
2266
2267
/*!
2268
@brief lexical analysis
2269
2270
This class organizes the lexical analysis during JSON deserialization.
2271
*/
2272
template<typename BasicJsonType>
2273
class lexer
2274
{
2275
    using number_integer_t = typename BasicJsonType::number_integer_t;
2276
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
2277
    using number_float_t = typename BasicJsonType::number_float_t;
2278
    using string_t = typename BasicJsonType::string_t;
2279
2280
  public:
2281
    /// token types for the parser
2282
    enum class token_type
2283
    {
2284
        uninitialized,    ///< indicating the scanner is uninitialized
2285
        literal_true,     ///< the `true` literal
2286
        literal_false,    ///< the `false` literal
2287
        literal_null,     ///< the `null` literal
2288
        value_string,     ///< a string -- use get_string() for actual value
2289
        value_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value
2290
        value_integer,    ///< a signed integer -- use get_number_integer() for actual value
2291
        value_float,      ///< an floating point number -- use get_number_float() for actual value
2292
        begin_array,      ///< the character for array begin `[`
2293
        begin_object,     ///< the character for object begin `{`
2294
        end_array,        ///< the character for array end `]`
2295
        end_object,       ///< the character for object end `}`
2296
        name_separator,   ///< the name separator `:`
2297
        value_separator,  ///< the value separator `,`
2298
        parse_error,      ///< indicating a parse error
2299
        end_of_input,     ///< indicating the end of the input buffer
2300
        literal_or_value  ///< a literal or the begin of a value (only for diagnostics)
2301
    };
2302
2303
    /// return name of values of type token_type (only used for errors)
2304
    static const char* token_type_name(const token_type t) noexcept
0
2305
    {
0
2306
        switch (t)
0
2307
        {
0
2308
            case token_type::uninitialized:
0
2309
                return "<uninitialized>";
0
2310
            case token_type::literal_true:
0
2311
                return "true literal";
0
2312
            case token_type::literal_false:
0
2313
                return "false literal";
0
2314
            case token_type::literal_null:
0
2315
                return "null literal";
0
2316
            case token_type::value_string:
0
2317
                return "string literal";
0
2318
            case lexer::token_type::value_unsigned:
0
2319
            case lexer::token_type::value_integer:
0
2320
            case lexer::token_type::value_float:
0
2321
                return "number literal";
0
2322
            case token_type::begin_array:
0
2323
                return "'['";
0
2324
            case token_type::begin_object:
0
2325
                return "'{'";
0
2326
            case token_type::end_array:
0
2327
                return "']'";
0
2328
            case token_type::end_object:
0
2329
                return "'}'";
0
2330
            case token_type::name_separator:
0
2331
                return "':'";
0
2332
            case token_type::value_separator:
0
2333
                return "','";
0
2334
            case token_type::parse_error:
0
2335
                return "<parse error>";
0
2336
            case token_type::end_of_input:
0
2337
                return "end of input";
0
2338
            case token_type::literal_or_value:
0
2339
                return "'[', '{', or a literal";
0
2340
            // LCOV_EXCL_START
0
2341
            default: // catch non-enum values
0
2342
                return "unknown token";
0
2343
                // LCOV_EXCL_STOP
0
2344
        }
0
2345
    }
2346
2347
    explicit lexer(detail::input_adapter_t&& adapter)
258
2348
        : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {}
2349
2350
    // delete because of pointer members
2351
    lexer(const lexer&) = delete;
2352
    lexer& operator=(lexer&) = delete;
2353
2354
  private:
2355
    /////////////////////
2356
    // locales
2357
    /////////////////////
2358
2359
    /// return the locale-dependent decimal point
2360
    static char get_decimal_point() noexcept
258
2361
    {
258
2362
        const auto loc = localeconv();
258
2363
        assert(loc != nullptr);
258
2364
        return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
258
2365
    }
2366
2367
    /////////////////////
2368
    // scan functions
2369
    /////////////////////
2370
2371
    /*!
2372
    @brief get codepoint from 4 hex characters following `\u`
2373
2374
    For input "\u c1 c2 c3 c4" the codepoint is:
2375
      (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4
2376
    = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)
2377
2378
    Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'
2379
    must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The
2380
    conversion is done by subtracting the offset (0x30, 0x37, and 0x57)
2381
    between the ASCII value of the character and the desired integer value.
2382
2383
    @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or
2384
            non-hex character)
2385
    */
2386
    int get_codepoint()
0
2387
    {
0
2388
        // this function only makes sense after reading `\u`
0
2389
        assert(current == 'u');
0
2390
        int codepoint = 0;
0
2391
0
2392
        const auto factors = { 12, 8, 4, 0 };
0
2393
        for (const auto factor : factors)
0
2394
        {
0
2395
            get();
0
2396
0
2397
            if (current >= '0' and current <= '9')
0
2398
            {
0
2399
                codepoint += ((current - 0x30) << factor);
0
2400
            }
0
2401
            else if (current >= 'A' and current <= 'F')
0
2402
            {
0
2403
                codepoint += ((current - 0x37) << factor);
0
2404
            }
0
2405
            else if (current >= 'a' and current <= 'f')
0
2406
            {
0
2407
                codepoint += ((current - 0x57) << factor);
0
2408
            }
0
2409
            else
0
2410
            {
0
2411
                return -1;
0
2412
            }
0
2413
        }
0
2414
0
2415
        assert(0x0000 <= codepoint and codepoint <= 0xFFFF);
0
2416
        return codepoint;
0
2417
    }
2418
2419
    /*!
2420
    @brief check if the next byte(s) are inside a given range
2421
2422
    Adds the current byte and, for each passed range, reads a new byte and
2423
    checks if it is inside the range. If a violation was detected, set up an
2424
    error message and return false. Otherwise, return true.
2425
2426
    @param[in] ranges  list of integers; interpreted as list of pairs of
2427
                       inclusive lower and upper bound, respectively
2428
2429
    @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,
2430
         1, 2, or 3 pairs. This precondition is enforced by an assertion.
2431
2432
    @return true if and only if no range violation was detected
2433
    */
2434
    bool next_byte_in_range(std::initializer_list<int> ranges)
0
2435
    {
0
2436
        assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6);
0
2437
        add(current);
0
2438
0
2439
        for (auto range = ranges.begin(); range != ranges.end(); ++range)
0
2440
        {
0
2441
            get();
0
2442
            if (JSON_LIKELY(*range <= current and current <= *(++range)))
0
2443
            {
0
2444
                add(current);
0
2445
            }
0
2446
            else
0
2447
            {
0
2448
                error_message = "invalid string: ill-formed UTF-8 byte";
0
2449
                return false;
0
2450
            }
0
2451
        }
0
2452
0
2453
        return true;
0
2454
    }
2455
2456
    /*!
2457
    @brief scan a string literal
2458
2459
    This function scans a string according to Sect. 7 of RFC 7159. While
2460
    scanning, bytes are escaped and copied into buffer token_buffer. Then the
2461
    function returns successfully, token_buffer is *not* null-terminated (as it
2462
    may contain \0 bytes), and token_buffer.size() is the number of bytes in the
2463
    string.
2464
2465
    @return token_type::value_string if string could be successfully scanned,
2466
            token_type::parse_error otherwise
2467
2468
    @note In case of errors, variable error_message contains a textual
2469
          description.
2470
    */
2471
    token_type scan_string()
90.3k
2472
    {
90.3k
2473
        // reset token_buffer (ignore opening quote)
90.3k
2474
        reset();
90.3k
2475
90.3k
2476
        // we entered the function by reading an open quote
90.3k
2477
        assert(current == '\"');
90.3k
2478
802k
2479
        while (true)
802k
2480
        {
802k
2481
            // get next character
711k
2482
            switch (get())
711k
2483
            {
711k
2484
                // end of file while parsing string
0
2485
                case std::char_traits<char>::eof():
0
2486
                {
0
2487
                    error_message = "invalid string: missing closing quote";
0
2488
                    return token_type::parse_error;
0
2489
                }
0
2490
0
2491
                // closing quote
90.3k
2492
                case '\"':
90.3k
2493
                {
90.3k
2494
                    return token_type::value_string;
0
2495
                }
0
2496
0
2497
                // escapes
0
2498
                case '\\':
0
2499
                {
0
2500
                    switch (get())
0
2501
                    {
0
2502
                        // quotation mark
0
2503
                        case '\"':
0
2504
                            add('\"');
0
2505
                            break;
0
2506
                        // reverse solidus
0
2507
                        case '\\':
0
2508
                            add('\\');
0
2509
                            break;
0
2510
                        // solidus
0
2511
                        case '/':
0
2512
                            add('/');
0
2513
                            break;
0
2514
                        // backspace
0
2515
                        case 'b':
0
2516
                            add('\b');
0
2517
                            break;
0
2518
                        // form feed
0
2519
                        case 'f':
0
2520
                            add('\f');
0
2521
                            break;
0
2522
                        // line feed
0
2523
                        case 'n':
0
2524
                            add('\n');
0
2525
                            break;
0
2526
                        // carriage return
0
2527
                        case 'r':
0
2528
                            add('\r');
0
2529
                            break;
0
2530
                        // tab
0
2531
                        case 't':
0
2532
                            add('\t');
0
2533
                            break;
0
2534
0
2535
                        // unicode escapes
0
2536
                        case 'u':
0
2537
                        {
0
2538
                            const int codepoint1 = get_codepoint();
0
2539
                            int codepoint = codepoint1; // start with codepoint1
0
2540
0
2541
                            if (JSON_UNLIKELY(codepoint1 == -1))
0
2542
                            {
0
2543
                                error_message = "invalid string: '\\u' must be followed by 4 hex digits";
0
2544
                                return token_type::parse_error;
0
2545
                            }
0
2546
0
2547
                            // check if code point is a high surrogate
0
2548
                            if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)
0
2549
                            {
0
2550
                                // expect next \uxxxx entry
0
2551
                                if (JSON_LIKELY(get() == '\\' and get() == 'u'))
0
2552
                                {
0
2553
                                    const int codepoint2 = get_codepoint();
0
2554
0
2555
                                    if (JSON_UNLIKELY(codepoint2 == -1))
0
2556
                                    {
0
2557
                                        error_message = "invalid string: '\\u' must be followed by 4 hex digits";
0
2558
                                        return token_type::parse_error;
0
2559
                                    }
0
2560
0
2561
                                    // check if codepoint2 is a low surrogate
0
2562
                                    if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))
0
2563
                                    {
0
2564
                                        // overwrite codepoint
0
2565
                                        codepoint =
0
2566
                                            // high surrogate occupies the most significant 22 bits
0
2567
                                            (codepoint1 << 10)
0
2568
                                            // low surrogate occupies the least significant 15 bits
0
2569
                                            + codepoint2
0
2570
                                            // there is still the 0xD800, 0xDC00 and 0x10000 noise
0
2571
                                            // in the result so we have to subtract with:
0
2572
                                            // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
0
2573
                                            - 0x35FDC00;
0
2574
                                    }
0
2575
                                    else
0
2576
                                    {
0
2577
                                        error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
0
2578
                                        return token_type::parse_error;
0
2579
                                    }
0
2580
                                }
0
2581
                                else
0
2582
                                {
0
2583
                                    error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
0
2584
                                    return token_type::parse_error;
0
2585
                                }
0
2586
                            }
0
2587
                            else
0
2588
                            {
0
2589
                                if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))
0
2590
                                {
0
2591
                                    error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
0
2592
                                    return token_type::parse_error;
0
2593
                                }
0
2594
                            }
0
2595
0
2596
                            // result of the above calculation yields a proper codepoint
0
2597
                            assert(0x00 <= codepoint and codepoint <= 0x10FFFF);
0
2598
0
2599
                            // translate codepoint into bytes
0
2600
                            if (codepoint < 0x80)
0
2601
                            {
0
2602
                                // 1-byte characters: 0xxxxxxx (ASCII)
0
2603
                                add(codepoint);
0
2604
                            }
0
2605
                            else if (codepoint <= 0x7FF)
0
2606
                            {
0
2607
                                // 2-byte characters: 110xxxxx 10xxxxxx
0
2608
                                add(0xC0 | (codepoint >> 6));
0
2609
                                add(0x80 | (codepoint & 0x3F));
0
2610
                            }
0
2611
                            else if (codepoint <= 0xFFFF)
0
2612
                            {
0
2613
                                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
0
2614
                                add(0xE0 | (codepoint >> 12));
0
2615
                                add(0x80 | ((codepoint >> 6) & 0x3F));
0
2616
                                add(0x80 | (codepoint & 0x3F));
0
2617
                            }
0
2618
                            else
0
2619
                            {
0
2620
                                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0
2621
                                add(0xF0 | (codepoint >> 18));
0
2622
                                add(0x80 | ((codepoint >> 12) & 0x3F));
0
2623
                                add(0x80 | ((codepoint >> 6) & 0x3F));
0
2624
                                add(0x80 | (codepoint & 0x3F));
0
2625
                            }
0
2626
0
2627
                            break;
0
2628
                        }
0
2629
0
2630
                        // other characters after escape
0
2631
                        default:
0
2632
                            error_message = "invalid string: forbidden character after backslash";
0
2633
                            return token_type::parse_error;
0
2634
                    }
0
2635
0
2636
                    break;
0
2637
                }
0
2638
0
2639
                // invalid control characters
0
2640
                case 0x00:
0
2641
                case 0x01:
0
2642
                case 0x02:
0
2643
                case 0x03:
0
2644
                case 0x04:
0
2645
                case 0x05:
0
2646
                case 0x06:
0
2647
                case 0x07:
0
2648
                case 0x08:
0
2649
                case 0x09:
0
2650
                case 0x0A:
0
2651
                case 0x0B:
0
2652
                case 0x0C:
0
2653
                case 0x0D:
0
2654
                case 0x0E:
0
2655
                case 0x0F:
0
2656
                case 0x10:
0
2657
                case 0x11:
0
2658
                case 0x12:
0
2659
                case 0x13:
0
2660
                case 0x14:
0
2661
                case 0x15:
0
2662
                case 0x16:
0
2663
                case 0x17:
0
2664
                case 0x18:
0
2665
                case 0x19:
0
2666
                case 0x1A:
0
2667
                case 0x1B:
0
2668
                case 0x1C:
0
2669
                case 0x1D:
0
2670
                case 0x1E:
0
2671
                case 0x1F:
0
2672
                {
0
2673
                    error_message = "invalid string: control character must be escaped";
0
2674
                    return token_type::parse_error;
0
2675
                }
0
2676
0
2677
                // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
711k
2678
                case 0x20:
711k
2679
                case 0x21:
711k
2680
                case 0x23:
711k
2681
                case 0x24:
711k
2682
                case 0x25:
711k
2683
                case 0x26:
711k
2684
                case 0x27:
711k
2685
                case 0x28:
711k
2686
                case 0x29:
711k
2687
                case 0x2A:
711k
2688
                case 0x2B:
711k
2689
                case 0x2C:
711k
2690
                case 0x2D:
711k
2691
                case 0x2E:
711k
2692
                case 0x2F:
711k
2693
                case 0x30:
711k
2694
                case 0x31:
711k
2695
                case 0x32:
711k
2696
                case 0x33:
711k
2697
                case 0x34:
711k
2698
                case 0x35:
711k
2699
                case 0x36:
711k
2700
                case 0x37:
711k
2701
                case 0x38:
711k
2702
                case 0x39:
711k
2703
                case 0x3A:
711k
2704
                case 0x3B:
711k
2705
                case 0x3C:
711k
2706
                case 0x3D:
711k
2707
                case 0x3E:
711k
2708
                case 0x3F:
711k
2709
                case 0x40:
711k
2710
                case 0x41:
711k
2711
                case 0x42:
711k
2712
                case 0x43:
711k
2713
                case 0x44:
711k
2714
                case 0x45:
711k
2715
                case 0x46:
711k
2716
                case 0x47:
711k
2717
                case 0x48:
711k
2718
                case 0x49:
711k
2719
                case 0x4A:
711k
2720
                case 0x4B:
711k
2721
                case 0x4C:
711k
2722
                case 0x4D:
711k
2723
                case 0x4E:
711k
2724
                case 0x4F:
711k
2725
                case 0x50:
711k
2726
                case 0x51:
711k
2727
                case 0x52:
711k
2728
                case 0x53:
711k
2729
                case 0x54:
711k
2730
                case 0x55:
711k
2731
                case 0x56:
711k
2732
                case 0x57:
711k
2733
                case 0x58:
711k
2734
                case 0x59:
711k
2735
                case 0x5A:
711k
2736
                case 0x5B:
711k
2737
                case 0x5D:
711k
2738
                case 0x5E:
711k
2739
                case 0x5F:
711k
2740
                case 0x60:
711k
2741
                case 0x61:
711k
2742
                case 0x62:
711k
2743
                case 0x63:
711k
2744
                case 0x64:
711k
2745
                case 0x65:
711k
2746
                case 0x66:
711k
2747
                case 0x67:
711k
2748
                case 0x68:
711k
2749
                case 0x69:
711k
2750
                case 0x6A:
711k
2751
                case 0x6B:
711k
2752
                case 0x6C:
711k
2753
                case 0x6D:
711k
2754
                case 0x6E:
711k
2755
                case 0x6F:
711k
2756
                case 0x70:
711k
2757
                case 0x71:
711k
2758
                case 0x72:
711k
2759
                case 0x73:
711k
2760
                case 0x74:
711k
2761
                case 0x75:
711k
2762
                case 0x76:
711k
2763
                case 0x77:
711k
2764
                case 0x78:
711k
2765
                case 0x79:
711k
2766
                case 0x7A:
711k
2767
                case 0x7B:
711k
2768
                case 0x7C:
711k
2769
                case 0x7D:
711k
2770
                case 0x7E:
711k
2771
                case 0x7F:
711k
2772
                {
711k
2773
                    add(current);
711k
2774
                    break;
711k
2775
                }
711k
2776
711k
2777
                // U+0080..U+07FF: bytes C2..DF 80..BF
0
2778
                case 0xC2:
0
2779
                case 0xC3:
0
2780
                case 0xC4:
0
2781
                case 0xC5:
0
2782
                case 0xC6:
0
2783
                case 0xC7:
0
2784
                case 0xC8:
0
2785
                case 0xC9:
0
2786
                case 0xCA:
0
2787
                case 0xCB:
0
2788
                case 0xCC:
0
2789
                case 0xCD:
0
2790
                case 0xCE:
0
2791
                case 0xCF:
0
2792
                case 0xD0:
0
2793
                case 0xD1:
0
2794
                case 0xD2:
0
2795
                case 0xD3:
0
2796
                case 0xD4:
0
2797
                case 0xD5:
0
2798
                case 0xD6:
0
2799
                case 0xD7:
0
2800
                case 0xD8:
0
2801
                case 0xD9:
0
2802
                case 0xDA:
0
2803
                case 0xDB:
0
2804
                case 0xDC:
0
2805
                case 0xDD:
0
2806
                case 0xDE:
0
2807
                case 0xDF:
0
2808
                {
0
2809
                    if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF})))
0
2810
                    {
0
2811
                        return token_type::parse_error;
0
2812
                    }
0
2813
                    break;
0
2814
                }
0
2815
0
2816
                // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
0
2817
                case 0xE0:
0
2818
                {
0
2819
                    if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
0
2820
                    {
0
2821
                        return token_type::parse_error;
0
2822
                    }
0
2823
                    break;
0
2824
                }
0
2825
0
2826
                // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
0
2827
                // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
0
2828
                case 0xE1:
0
2829
                case 0xE2:
0
2830
                case 0xE3:
0
2831
                case 0xE4:
0
2832
                case 0xE5:
0
2833
                case 0xE6:
0
2834
                case 0xE7:
0
2835
                case 0xE8:
0
2836
                case 0xE9:
0
2837
                case 0xEA:
0
2838
                case 0xEB:
0
2839
                case 0xEC:
0
2840
                case 0xEE:
0
2841
                case 0xEF:
0
2842
                {
0
2843
                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
0
2844
                    {
0
2845
                        return token_type::parse_error;
0
2846
                    }
0
2847
                    break;
0
2848
                }
0
2849
0
2850
                // U+D000..U+D7FF: bytes ED 80..9F 80..BF
0
2851
                case 0xED:
0
2852
                {
0
2853
                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
0
2854
                    {
0
2855
                        return token_type::parse_error;
0
2856
                    }
0
2857
                    break;
0
2858
                }
0
2859
0
2860
                // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
0
2861
                case 0xF0:
0
2862
                {
0
2863
                    if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
0
2864
                    {
0
2865
                        return token_type::parse_error;
0
2866
                    }
0
2867
                    break;
0
2868
                }
0
2869
0
2870
                // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
0
2871
                case 0xF1:
0
2872
                case 0xF2:
0
2873
                case 0xF3:
0
2874
                {
0
2875
                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
0
2876
                    {
0
2877
                        return token_type::parse_error;
0
2878
                    }
0
2879
                    break;
0
2880
                }
0
2881
0
2882
                // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
0
2883
                case 0xF4:
0
2884
                {
0
2885
                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
0
2886
                    {
0
2887
                        return token_type::parse_error;
0
2888
                    }
0
2889
                    break;
0
2890
                }
0
2891
0
2892
                // remaining bytes (80..C1 and F5..FF) are ill-formed
0
2893
                default:
0
2894
                {
0
2895
                    error_message = "invalid string: ill-formed UTF-8 byte";
0
2896
                    return token_type::parse_error;
0
2897
                }
711k
2898
            }
802k
2899
        }
90.3k
2900
    }
2901
2902
    static void strtof(float& f, const char* str, char** endptr) noexcept
2903
    {
2904
        f = std::strtof(str, endptr);
2905
    }
2906
2907
    static void strtof(double& f, const char* str, char** endptr) noexcept
16.8k
2908
    {
16.8k
2909
        f = std::strtod(str, endptr);
16.8k
2910
    }
2911
2912
    static void strtof(long double& f, const char* str, char** endptr) noexcept
2913
    {
2914
        f = std::strtold(str, endptr);
2915
    }
2916
2917
    /*!
2918
    @brief scan a number literal
2919
2920
    This function scans a string according to Sect. 6 of RFC 7159.
2921
2922
    The function is realized with a deterministic finite state machine derived
2923
    from the grammar described in RFC 7159. Starting in state "init", the
2924
    input is read and used to determined the next state. Only state "done"
2925
    accepts the number. State "error" is a trap state to model errors. In the
2926
    table below, "anything" means any character but the ones listed before.
2927
2928
    state    | 0        | 1-9      | e E      | +       | -       | .        | anything
2929
    ---------|----------|----------|----------|---------|---------|----------|-----------
2930
    init     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]
2931
    minus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]
2932
    zero     | done     | done     | exponent | done    | done    | decimal1 | done
2933
    any1     | any1     | any1     | exponent | done    | done    | decimal1 | done
2934
    decimal1 | decimal2 | [error]  | [error]  | [error] | [error] | [error]  | [error]
2935
    decimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done
2936
    exponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]
2937
    sign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]
2938
    any2     | any2     | any2     | done     | done    | done    | done     | done
2939
2940
    The state machine is realized with one label per state (prefixed with
2941
    "scan_number_") and `goto` statements between them. The state machine
2942
    contains cycles, but any cycle can be left when EOF is read. Therefore,
2943
    the function is guaranteed to terminate.
2944
2945
    During scanning, the read bytes are stored in token_buffer. This string is
2946
    then converted to a signed integer, an unsigned integer, or a
2947
    floating-point number.
2948
2949
    @return token_type::value_unsigned, token_type::value_integer, or
2950
            token_type::value_float if number could be successfully scanned,
2951
            token_type::parse_error otherwise
2952
2953
    @note The scanner is independent of the current locale. Internally, the
2954
          locale's decimal point is used instead of `.` to work with the
2955
          locale-dependent converters.
2956
    */
2957
    token_type scan_number()
42.1k
2958
    {
42.1k
2959
        // reset token_buffer to store the number's bytes
42.1k
2960
        reset();
42.1k
2961
42.1k
2962
        // the type of the parsed number; initially set to unsigned; will be
42.1k
2963
        // changed if minus sign, decimal point or exponent is read
42.1k
2964
        token_type number_type = token_type::value_unsigned;
42.1k
2965
42.1k
2966
        // state (init): we just found out we need to scan a number
0
2967
        switch (current)
0
2968
        {
2.69k
2969
            case '-':
2.69k
2970
            {
2.69k
2971
                add(current);
2.69k
2972
                goto scan_number_minus;
2.69k
2973
            }
2.69k
2974
5.68k
2975
            case '0':
5.68k
2976
            {
5.68k
2977
                add(current);
5.68k
2978
                goto scan_number_zero;
2.69k
2979
            }
2.69k
2980
33.7k
2981
            case '1':
33.7k
2982
            case '2':
33.7k
2983
            case '3':
33.7k
2984
            case '4':
33.7k
2985
            case '5':
33.7k
2986
            case '6':
33.7k
2987
            case '7':
33.7k
2988
            case '8':
33.7k
2989
            case '9':
33.7k
2990
            {
33.7k
2991
                add(current);
33.7k
2992
                goto scan_number_any1;
33.7k
2993
            }
33.7k
2994
33.7k
2995
            // LCOV_EXCL_START
0
2996
            default:
0
2997
            {
0
2998
                // all other characters are rejected outside scan_number()
0
2999
                assert(false);
0
3000
            }
0
3001
                // LCOV_EXCL_STOP
0
3002
        }
42.1k
3003
2.69k
3004
scan_number_minus:
2.69k
3005
        // state: we just parsed a leading minus sign
2.69k
3006
        number_type = token_type::value_integer;
0
3007
        switch (get())
0
3008
        {
0
3009
            case '0':
0
3010
            {
0
3011
                add(current);
0
3012
                goto scan_number_zero;
0
3013
            }
0
3014
2.69k
3015
            case '1':
2.69k
3016
            case '2':
2.69k
3017
            case '3':
2.69k
3018
            case '4':
2.69k
3019
            case '5':
2.69k
3020
            case '6':
2.69k
3021
            case '7':
2.69k
3022
            case '8':
2.69k
3023
            case '9':
2.69k
3024
            {
2.69k
3025
                add(current);
2.69k
3026
                goto scan_number_any1;
2.69k
3027
            }
2.69k
3028
0
3029
            default:
0
3030
            {
0
3031
                error_message = "invalid number; expected digit after '-'";
0
3032
                return token_type::parse_error;
2.69k
3033
            }
0
3034
        }
2.69k
3035
5.68k
3036
scan_number_zero:
5.68k
3037
        // state: we just parse a zero (maybe with a leading minus sign)
0
3038
        switch (get())
0
3039
        {
58
3040
            case '.':
58
3041
            {
58
3042
                add(decimal_point_char);
58
3043
                goto scan_number_decimal1;
58
3044
            }
58
3045
0
3046
            case 'e':
0
3047
            case 'E':
0
3048
            {
0
3049
                add(current);
0
3050
                goto scan_number_exponent;
0
3051
            }
0
3052
5.62k
3053
            default:
5.62k
3054
                goto scan_number_done;
0
3055
        }
5.68k
3056
124k
3057
scan_number_any1:
124k
3058
        // state: we just parsed a number 0-9 (maybe with a leading minus sign)
0
3059
        switch (get())
0
3060
        {
87.8k
3061
            case '0':
87.8k
3062
            case '1':
87.8k
3063
            case '2':
87.8k
3064
            case '3':
87.8k
3065
            case '4':
87.8k
3066
            case '5':
87.8k
3067
            case '6':
87.8k
3068
            case '7':
87.8k
3069
            case '8':
87.8k
3070
            case '9':
87.8k
3071
            {
87.8k
3072
                add(current);
87.8k
3073
                goto scan_number_any1;
87.8k
3074
            }
87.8k
3075
16.8k
3076
            case '.':
16.8k
3077
            {
16.8k
3078
                add(decimal_point_char);
16.8k
3079
                goto scan_number_decimal1;
87.8k
3080
            }
87.8k
3081
0
3082
            case 'e':
0
3083
            case 'E':
0
3084
            {
0
3085
                add(current);
0
3086
                goto scan_number_exponent;
0
3087
            }
0
3088
19.6k
3089
            default:
19.6k
3090
                goto scan_number_done;
0
3091
        }
124k
3092
16.8k
3093
scan_number_decimal1:
16.8k
3094
        // state: we just parsed a decimal point
16.8k
3095
        number_type = token_type::value_float;
0
3096
        switch (get())
0
3097
        {
16.8k
3098
            case '0':
16.8k
3099
            case '1':
16.8k
3100
            case '2':
16.8k
3101
            case '3':
16.8k
3102
            case '4':
16.8k
3103
            case '5':
16.8k
3104
            case '6':
16.8k
3105
            case '7':
16.8k
3106
            case '8':
16.8k
3107
            case '9':
16.8k
3108
            {
16.8k
3109
                add(current);
16.8k
3110
                goto scan_number_decimal2;
16.8k
3111
            }
16.8k
3112
0
3113
            default:
0
3114
            {
0
3115
                error_message = "invalid number; expected digit after '.'";
0
3116
                return token_type::parse_error;
16.8k
3117
            }
0
3118
        }
16.8k
3119
72.1k
3120
scan_number_decimal2:
72.1k
3121
        // we just parsed at least one number after a decimal point
0
3122
        switch (get())
0
3123
        {
55.2k
3124
            case '0':
55.2k
3125
            case '1':
55.2k
3126
            case '2':
55.2k
3127
            case '3':
55.2k
3128
            case '4':
55.2k
3129
            case '5':
55.2k
3130
            case '6':
55.2k
3131
            case '7':
55.2k
3132
            case '8':
55.2k
3133
            case '9':
55.2k
3134
            {
55.2k
3135
                add(current);
55.2k
3136
                goto scan_number_decimal2;
55.2k
3137
            }
55.2k
3138
0
3139
            case 'e':
0
3140
            case 'E':
0
3141
            {
0
3142
                add(current);
0
3143
                goto scan_number_exponent;
0
3144
            }
0
3145
16.8k
3146
            default:
16.8k
3147
                goto scan_number_done;
0
3148
        }
72.1k
3149
0
3150
scan_number_exponent:
0
3151
        // we just parsed an exponent
0
3152
        number_type = token_type::value_float;
0
3153
        switch (get())
0
3154
        {
0
3155
            case '+':
0
3156
            case '-':
0
3157
            {
0
3158
                add(current);
0
3159
                goto scan_number_sign;
0
3160
            }
0
3161
0
3162
            case '0':
0
3163
            case '1':
0
3164
            case '2':
0
3165
            case '3':
0
3166
            case '4':
0
3167
            case '5':
0
3168
            case '6':
0
3169
            case '7':
0
3170
            case '8':
0
3171
            case '9':
0
3172
            {
0
3173
                add(current);
0
3174
                goto scan_number_any2;
0
3175
            }
0
3176
0
3177
            default:
0
3178
            {
0
3179
                error_message =
0
3180
                    "invalid number; expected '+', '-', or digit after exponent";
0
3181
                return token_type::parse_error;
0
3182
            }
0
3183
        }
0
3184
0
3185
scan_number_sign:
0
3186
        // we just parsed an exponent sign
0
3187
        switch (get())
0
3188
        {
0
3189
            case '0':
0
3190
            case '1':
0
3191
            case '2':
0
3192
            case '3':
0
3193
            case '4':
0
3194
            case '5':
0
3195
            case '6':
0
3196
            case '7':
0
3197
            case '8':
0
3198
            case '9':
0
3199
            {
0
3200
                add(current);
0
3201
                goto scan_number_any2;
0
3202
            }
0
3203
0
3204
            default:
0
3205
            {
0
3206
                error_message = "invalid number; expected digit after exponent sign";
0
3207
                return token_type::parse_error;
0
3208
            }
0
3209
        }
0
3210
0
3211
scan_number_any2:
0
3212
        // we just parsed a number after the exponent or exponent sign
0
3213
        switch (get())
0
3214
        {
0
3215
            case '0':
0
3216
            case '1':
0
3217
            case '2':
0
3218
            case '3':
0
3219
            case '4':
0
3220
            case '5':
0
3221
            case '6':
0
3222
            case '7':
0
3223
            case '8':
0
3224
            case '9':
0
3225
            {
0
3226
                add(current);
0
3227
                goto scan_number_any2;
0
3228
            }
0
3229
0
3230
            default:
0
3231
                goto scan_number_done;
0
3232
        }
0
3233
42.1k
3234
scan_number_done:
42.1k
3235
        // unget the character after the number (we only read it to know that
42.1k
3236
        // we are done scanning a number)
42.1k
3237
        unget();
42.1k
3238
42.1k
3239
        char* endptr = nullptr;
42.1k
3240
        errno = 0;
42.1k
3241
42.1k
3242
        // try to parse integers first and fall back to floats
42.1k
3243
        if (number_type == token_type::value_unsigned)
22.6k
3244
        {
22.6k
3245
            const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
22.6k
3246
22.6k
3247
            // we checked the number format before
22.6k
3248
            assert(endptr == token_buffer.data() + token_buffer.size());
22.6k
3249
22.6k
3250
            if (errno == 0)
22.6k
3251
            {
22.6k
3252
                value_unsigned = static_cast<number_unsigned_t>(x);
22.6k
3253
                if (value_unsigned == x)
22.6k
3254
                {
22.6k
3255
                    return token_type::value_unsigned;
22.6k
3256
                }
22.6k
3257
            }
22.6k
3258
        }
19.5k
3259
        else if (number_type == token_type::value_integer)
2.69k
3260
        {
2.69k
3261
            const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
2.69k
3262
2.69k
3263
            // we checked the number format before
2.69k
3264
            assert(endptr == token_buffer.data() + token_buffer.size());
2.69k
3265
2.69k
3266
            if (errno == 0)
2.69k
3267
            {
2.69k
3268
                value_integer = static_cast<number_integer_t>(x);
2.69k
3269
                if (value_integer == x)
2.69k
3270
                {
2.69k
3271
                    return token_type::value_integer;
2.69k
3272
                }
2.69k
3273
            }
2.69k
3274
        }
42.1k
3275
42.1k
3276
        // this code is reached if we parse a floating-point number or if an
42.1k
3277
        // integer conversion above failed
16.8k
3278
        strtof(value_float, token_buffer.data(), &endptr);
16.8k
3279
16.8k
3280
        // we checked the number format before
16.8k
3281
        assert(endptr == token_buffer.data() + token_buffer.size());
16.8k
3282
16.8k
3283
        return token_type::value_float;
42.1k
3284
    }
3285
3286
    /*!
3287
    @param[in] literal_text  the literal text to expect
3288
    @param[in] length        the length of the passed literal text
3289
    @param[in] return_type   the token type to return on success
3290
    */
3291
    token_type scan_literal(const char* literal_text, const std::size_t length,
3292
                            token_type return_type)
299
3293
    {
299
3294
        assert(current == literal_text[0]);
1.19k
3295
        for (std::size_t i = 1; i < length; ++i)
897
3296
        {
897
3297
            if (JSON_UNLIKELY(get() != literal_text[i]))
0
3298
            {
0
3299
                error_message = "invalid literal";
0
3300
                return token_type::parse_error;
0
3301
            }
897
3302
        }
299
3303
        return return_type;
299
3304
    }
3305
3306
    /////////////////////
3307
    // input management
3308
    /////////////////////
3309
3310
    /// reset token_buffer; current character is beginning of token
3311
    void reset() noexcept
132k
3312
    {
132k
3313
        token_buffer.clear();
132k
3314
        token_string.clear();
132k
3315
        token_string.push_back(std::char_traits<char>::to_char_type(current));
132k
3316
    }
3317
3318
    /*
3319
    @brief get next character from the input
3320
3321
    This function provides the interface to the used input adapter. It does
3322
    not throw in case the input reached EOF, but returns a
3323
    `std::char_traits<char>::eof()` in that case.  Stores the scanned characters
3324
    for use in error messages.
3325
3326
    @return character read from the input
3327
    */
3328
    std::char_traits<char>::int_type get()
1.36M
3329
    {
1.36M
3330
        ++chars_read;
1.36M
3331
        if (next_unget)
42.4k
3332
        {
42.4k
3333
            // just reset the next_unget variable and work with current
42.4k
3334
            next_unget = false;
42.4k
3335
        }
1.36M
3336
        else
1.32M
3337
        {
1.32M
3338
            current = ia->get_character();
1.32M
3339
        }
1.36M
3340
1.36M
3341
        if (JSON_LIKELY(current != std::char_traits<char>::eof()))
1.36M
3342
        {
1.36M
3343
            token_string.push_back(std::char_traits<char>::to_char_type(current));
1.36M
3344
        }
1.36M
3345
        return current;
1.36M
3346
    }
3347
3348
    /*!
3349
    @brief unget current character (read it again on next get)
3350
3351
    We implement unget by setting variable next_unget to true. The input is not
3352
    changed - we just simulate ungetting by modifying chars_read and
3353
    token_string. The next call to get() will behave as if the unget character
3354
    is read again.
3355
    */
3356
    void unget()
42.4k
3357
    {
42.4k
3358
        next_unget = true;
42.4k
3359
        --chars_read;
42.4k
3360
        if (JSON_LIKELY(current != std::char_traits<char>::eof()))
42.4k
3361
        {
42.4k
3362
            assert(token_string.size() != 0);
42.4k
3363
            token_string.pop_back();
42.4k
3364
        }
42.4k
3365
    }
3366
3367
    /// add a character to token_buffer
3368
    void add(int c)
933k
3369
    {
933k
3370
        token_buffer.push_back(std::char_traits<char>::to_char_type(c));
933k
3371
    }
3372
3373
  public:
3374
    /////////////////////
3375
    // value getters
3376
    /////////////////////
3377
3378
    /// return integer value
3379
    constexpr number_integer_t get_number_integer() const noexcept
2.69k
3380
    {
2.69k
3381
        return value_integer;
2.69k
3382
    }
3383
3384
    /// return unsigned integer value
3385
    constexpr number_unsigned_t get_number_unsigned() const noexcept
22.6k
3386
    {
22.6k
3387
        return value_unsigned;
22.6k
3388
    }
3389
3390
    /// return floating-point value
3391
    constexpr number_float_t get_number_float() const noexcept
16.8k
3392
    {
16.8k
3393
        return value_float;
16.8k
3394
    }
3395
3396
    /// return current string value (implicitly resets the token; useful only once)
3397
    string_t& get_string()
107k
3398
    {
107k
3399
        return token_buffer;
107k
3400
    }
3401
3402
    /////////////////////
3403
    // diagnostics
3404
    /////////////////////
3405
3406
    /// return position of last read token
3407
    constexpr std::size_t get_position() const noexcept
0
3408
    {
0
3409
        return chars_read;
0
3410
    }
3411
3412
    /// return the last read token (for errors only).  Will never contain EOF
3413
    /// (an arbitrary value that is not a valid char value, often -1), because
3414
    /// 255 may legitimately occur.  May contain NUL, which should be escaped.
3415
    std::string get_token_string() const
0
3416
    {
0
3417
        // escape control characters
0
3418
        std::string result;
0
3419
        for (const auto c : token_string)
0
3420
        {
0
3421
            if ('\x00' <= c and c <= '\x1F')
0
3422
            {
0
3423
                // escape control characters
0
3424
                char cs[9];
0
3425
                snprintf(cs, 9, "<U+%.4X>", static_cast<unsigned char>(c));
0
3426
                result += cs;
0
3427
            }
0
3428
            else
0
3429
            {
0
3430
                // add character as is
0
3431
                result.push_back(c);
0
3432
            }
0
3433
        }
0
3434
0
3435
        return result;
0
3436
    }
3437
3438
    /// return syntax error message
3439
    constexpr const char* get_error_message() const noexcept
0
3440
    {
0
3441
        return error_message;
0
3442
    }
3443
3444
    /////////////////////
3445
    // actual scanner
3446
    /////////////////////
3447
3448
    /*!
3449
    @brief skip the UTF-8 byte order mark
3450
    @return true iff there is no BOM or the correct BOM has been skipped
3451
    */
3452
    bool skip_bom()
258
3453
    {
258
3454
        if (get() == 0xEF)
0
3455
        {
0
3456
            if (get() == 0xBB and get() == 0xBF)
0
3457
            {
0
3458
                // we completely parsed the BOM
0
3459
                return true;
0
3460
            }
0
3461
            else
0
3462
            {
0
3463
                // after reading 0xEF, an unexpected character followed
0
3464
                return false;
0
3465
            }
0
3466
        }
258
3467
        else
258
3468
        {
258
3469
            // the first character is not the beginning of the BOM; unget it to
258
3470
            // process is later
258
3471
            unget();
258
3472
            return true;
258
3473
        }
258
3474
    }
3475
3476
    token_type scan()
295k
3477
    {
295k
3478
        // initially, skip the BOM
295k
3479
        if (chars_read == 0 and not skip_bom())
0
3480
        {
0
3481
            error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
0
3482
            return token_type::parse_error;
0
3483
        }
295k
3484
295k
3485
        // read next character and ignore whitespace
295k
3486
        do
344k
3487
        {
344k
3488
            get();
344k
3489
        }
344k
3490
        while (current == ' ' or current == '\t' or current == '\n' or current == '\r');
295k
3491
0
3492
        switch (current)
0
3493
        {
0
3494
            // structural characters
178
3495
            case '[':
178
3496
                return token_type::begin_array;
178
3497
            case ']':
178
3498
                return token_type::end_array;
14.9k
3499
            case '{':
14.9k
3500
                return token_type::begin_object;
14.9k
3501
            case '}':
14.9k
3502
                return token_type::end_object;
72.4k
3503
            case ':':
72.4k
3504
                return token_type::name_separator;
60.1k
3505
            case ',':
60.1k
3506
                return token_type::value_separator;
178
3507
178
3508
            // literals
179
3509
            case 't':
179
3510
                return scan_literal("true", 4, token_type::literal_true);
0
3511
            case 'f':
0
3512
                return scan_literal("false", 5, token_type::literal_false);
120
3513
            case 'n':
120
3514
                return scan_literal("null", 4, token_type::literal_null);
178
3515
178
3516
            // string
90.3k
3517
            case '\"':
90.3k
3518
                return scan_string();
178
3519
178
3520
            // number
42.1k
3521
            case '-':
42.1k
3522
            case '0':
42.1k
3523
            case '1':
42.1k
3524
            case '2':
42.1k
3525
            case '3':
42.1k
3526
            case '4':
42.1k
3527
            case '5':
42.1k
3528
            case '6':
42.1k
3529
            case '7':
42.1k
3530
            case '8':
42.1k
3531
            case '9':
42.1k
3532
                return scan_number();
42.1k
3533
42.1k
3534
            // end of input (the null byte is needed when parsing from
42.1k
3535
            // string literals)
201
3536
            case '\0':
201
3537
            case std::char_traits<char>::eof():
201
3538
                return token_type::end_of_input;
201
3539
201
3540
            // error
0
3541
            default:
0
3542
                error_message = "invalid literal";
0
3543
                return token_type::parse_error;
0
3544
        }
295k
3545
    }
3546
3547
  private:
3548
    /// input adapter
3549
    detail::input_adapter_t ia = nullptr;
3550
3551
    /// the current character
3552
    std::char_traits<char>::int_type current = std::char_traits<char>::eof();
3553
3554
    /// whether the next get() call should just return current
3555
    bool next_unget = false;
3556
3557
    /// the number of characters read
3558
    std::size_t chars_read = 0;
3559
3560
    /// raw input token string (for error messages)
3561
    std::vector<char> token_string {};
3562
3563
    /// buffer for variable-length tokens (numbers, strings)
3564
    string_t token_buffer {};
3565
3566
    /// a description of occurred lexer errors
3567
    const char* error_message = "";
3568
3569
    // number values
3570
    number_integer_t value_integer = 0;
3571
    number_unsigned_t value_unsigned = 0;
3572
    number_float_t value_float = 0;
3573
3574
    /// the decimal point
3575
    const char decimal_point_char = '.';
3576
};
3577
}
3578
}
3579
3580
// #include <nlohmann/detail/input/parser.hpp>
3581
3582
3583
#include <cassert> // assert
3584
#include <cmath> // isfinite
3585
#include <cstdint> // uint8_t
3586
#include <functional> // function
3587
#include <string> // string
3588
#include <utility> // move
3589
3590
// #include <nlohmann/detail/exceptions.hpp>
3591
3592
// #include <nlohmann/detail/macro_scope.hpp>
3593
3594
// #include <nlohmann/detail/meta/is_sax.hpp>
3595
3596
3597
#include <cstdint> // size_t
3598
#include <utility> // declval
3599
3600
// #include <nlohmann/detail/meta/detected.hpp>
3601
3602
// #include <nlohmann/detail/meta/type_traits.hpp>
3603
3604
3605
namespace nlohmann
3606
{
3607
namespace detail
3608
{
3609
template <typename T>
3610
using null_function_t = decltype(std::declval<T&>().null());
3611
3612
template <typename T>
3613
using boolean_function_t =
3614
    decltype(std::declval<T&>().boolean(std::declval<bool>()));
3615
3616
template <typename T, typename Integer>
3617
using number_integer_function_t =
3618
    decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
3619
3620
template <typename T, typename Unsigned>
3621
using number_unsigned_function_t =
3622
    decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
3623
3624
template <typename T, typename Float, typename String>
3625
using number_float_function_t = decltype(std::declval<T&>().number_float(
3626
                                    std::declval<Float>(), std::declval<const String&>()));
3627
3628
template <typename T, typename String>
3629
using string_function_t =
3630
    decltype(std::declval<T&>().string(std::declval<String&>()));
3631
3632
template <typename T>
3633
using start_object_function_t =
3634
    decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
3635
3636
template <typename T, typename String>
3637
using key_function_t =
3638
    decltype(std::declval<T&>().key(std::declval<String&>()));
3639
3640
template <typename T>
3641
using end_object_function_t = decltype(std::declval<T&>().end_object());
3642
3643
template <typename T>
3644
using start_array_function_t =
3645
    decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
3646
3647
template <typename T>
3648
using end_array_function_t = decltype(std::declval<T&>().end_array());
3649
3650
template <typename T, typename Exception>
3651
using parse_error_function_t = decltype(std::declval<T&>().parse_error(
3652
        std::declval<std::size_t>(), std::declval<const std::string&>(),
3653
        std::declval<const Exception&>()));
3654
3655
template <typename SAX, typename BasicJsonType>
3656
struct is_sax
3657
{
3658
  private:
3659
    static_assert(is_basic_json<BasicJsonType>::value,
3660
                  "BasicJsonType must be of type basic_json<...>");
3661
3662
    using number_integer_t = typename BasicJsonType::number_integer_t;
3663
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
3664
    using number_float_t = typename BasicJsonType::number_float_t;
3665
    using string_t = typename BasicJsonType::string_t;
3666
    using exception_t = typename BasicJsonType::exception;
3667
3668
  public:
3669
    static constexpr bool value =
3670
        is_detected_exact<bool, null_function_t, SAX>::value &&
3671
        is_detected_exact<bool, boolean_function_t, SAX>::value &&
3672
        is_detected_exact<bool, number_integer_function_t, SAX,
3673
        number_integer_t>::value &&
3674
        is_detected_exact<bool, number_unsigned_function_t, SAX,
3675
        number_unsigned_t>::value &&
3676
        is_detected_exact<bool, number_float_function_t, SAX, number_float_t,
3677
        string_t>::value &&
3678
        is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
3679
        is_detected_exact<bool, start_object_function_t, SAX>::value &&
3680
        is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
3681
        is_detected_exact<bool, end_object_function_t, SAX>::value &&
3682
        is_detected_exact<bool, start_array_function_t, SAX>::value &&
3683
        is_detected_exact<bool, end_array_function_t, SAX>::value &&
3684
        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
3685
};
3686
3687
template <typename SAX, typename BasicJsonType>
3688
struct is_sax_static_asserts
3689
{
3690
  private:
3691
    static_assert(is_basic_json<BasicJsonType>::value,
3692
                  "BasicJsonType must be of type basic_json<...>");
3693
3694
    using number_integer_t = typename BasicJsonType::number_integer_t;
3695
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
3696
    using number_float_t = typename BasicJsonType::number_float_t;
3697
    using string_t = typename BasicJsonType::string_t;
3698
    using exception_t = typename BasicJsonType::exception;
3699
3700
  public:
3701
    static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
3702
                  "Missing/invalid function: bool null()");
3703
    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
3704
                  "Missing/invalid function: bool boolean(bool)");
3705
    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
3706
                  "Missing/invalid function: bool boolean(bool)");
3707
    static_assert(
3708
        is_detected_exact<bool, number_integer_function_t, SAX,
3709
        number_integer_t>::value,
3710
        "Missing/invalid function: bool number_integer(number_integer_t)");
3711
    static_assert(
3712
        is_detected_exact<bool, number_unsigned_function_t, SAX,
3713
        number_unsigned_t>::value,
3714
        "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
3715
    static_assert(is_detected_exact<bool, number_float_function_t, SAX,
3716
                  number_float_t, string_t>::value,
3717
                  "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
3718
    static_assert(
3719
        is_detected_exact<bool, string_function_t, SAX, string_t>::value,
3720
        "Missing/invalid function: bool string(string_t&)");
3721
    static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
3722
                  "Missing/invalid function: bool start_object(std::size_t)");
3723
    static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
3724
                  "Missing/invalid function: bool key(string_t&)");
3725
    static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
3726
                  "Missing/invalid function: bool end_object()");
3727
    static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
3728
                  "Missing/invalid function: bool start_array(std::size_t)");
3729
    static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
3730
                  "Missing/invalid function: bool end_array()");
3731
    static_assert(
3732
        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
3733
        "Missing/invalid function: bool parse_error(std::size_t, const "
3734
        "std::string&, const exception&)");
3735
};
3736
}
3737
}
3738
3739
// #include <nlohmann/detail/input/input_adapters.hpp>
3740
3741
// #include <nlohmann/detail/input/json_sax.hpp>
3742
3743
3744
#include <cstddef>
3745
#include <string>
3746
#include <vector>
3747
3748
// #include <nlohmann/detail/input/parser.hpp>
3749
3750
// #include <nlohmann/detail/exceptions.hpp>
3751
3752
3753
namespace nlohmann
3754
{
3755
3756
/*!
3757
@brief SAX interface
3758
3759
This class describes the SAX interface used by @ref nlohmann::json::sax_parse.
3760
Each function is called in different situations while the input is parsed. The
3761
boolean return value informs the parser whether to continue processing the
3762
input.
3763
*/
3764
template<typename BasicJsonType>
3765
struct json_sax
3766
{
3767
    /// type for (signed) integers
3768
    using number_integer_t = typename BasicJsonType::number_integer_t;
3769
    /// type for unsigned integers
3770
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
3771
    /// type for floating-point numbers
3772
    using number_float_t = typename BasicJsonType::number_float_t;
3773
    /// type for strings
3774
    using string_t = typename BasicJsonType::string_t;
3775
3776
    /*!
3777
    @brief a null value was read
3778
    @return whether parsing should proceed
3779
    */
3780
    virtual bool null() = 0;
3781
3782
    /*!
3783
    @brief a boolean value was read
3784
    @param[in] val  boolean value
3785
    @return whether parsing should proceed
3786
    */
3787
    virtual bool boolean(bool val) = 0;
3788
3789
    /*!
3790
    @brief an integer number was read
3791
    @param[in] val  integer value
3792
    @return whether parsing should proceed
3793
    */
3794
    virtual bool number_integer(number_integer_t val) = 0;
3795
3796
    /*!
3797
    @brief an unsigned integer number was read
3798
    @param[in] val  unsigned integer value
3799
    @return whether parsing should proceed
3800
    */
3801
    virtual bool number_unsigned(number_unsigned_t val) = 0;
3802
3803
    /*!
3804
    @brief an floating-point number was read
3805
    @param[in] val  floating-point value
3806
    @param[in] s    raw token value
3807
    @return whether parsing should proceed
3808
    */
3809
    virtual bool number_float(number_float_t val, const string_t& s) = 0;
3810
3811
    /*!
3812
    @brief a string was read
3813
    @param[in] val  string value
3814
    @return whether parsing should proceed
3815
    @note It is safe to move the passed string.
3816
    */
3817
    virtual bool string(string_t& val) = 0;
3818
3819
    /*!
3820
    @brief the beginning of an object was read
3821
    @param[in] elements  number of object elements or -1 if unknown
3822
    @return whether parsing should proceed
3823
    @note binary formats may report the number of elements
3824
    */
3825
    virtual bool start_object(std::size_t elements) = 0;
3826
3827
    /*!
3828
    @brief an object key was read
3829
    @param[in] val  object key
3830
    @return whether parsing should proceed
3831
    @note It is safe to move the passed string.
3832
    */
3833
    virtual bool key(string_t& val) = 0;
3834
3835
    /*!
3836
    @brief the end of an object was read
3837
    @return whether parsing should proceed
3838
    */
3839
    virtual bool end_object() = 0;
3840
3841
    /*!
3842
    @brief the beginning of an array was read
3843
    @param[in] elements  number of array elements or -1 if unknown
3844
    @return whether parsing should proceed
3845
    @note binary formats may report the number of elements
3846
    */
3847
    virtual bool start_array(std::size_t elements) = 0;
3848
3849
    /*!
3850
    @brief the end of an array was read
3851
    @return whether parsing should proceed
3852
    */
3853
    virtual bool end_array() = 0;
3854
3855
    /*!
3856
    @brief a parse error occurred
3857
    @param[in] position    the position in the input where the error occurs
3858
    @param[in] last_token  the last read token
3859
    @param[in] error_msg   a detailed error message
3860
    @return whether parsing should proceed (must return false)
3861
    */
3862
    virtual bool parse_error(std::size_t position,
3863
                             const std::string& last_token,
3864
                             const detail::exception& ex) = 0;
3865
3866
    virtual ~json_sax() = default;
3867
};
3868
3869
3870
namespace detail
3871
{
3872
/*!
3873
@brief SAX implementation to create a JSON value from SAX events
3874
3875
This class implements the @ref json_sax interface and processes the SAX events
3876
to create a JSON value which makes it basically a DOM parser. The structure or
3877
hierarchy of the JSON value is managed by the stack `ref_stack` which contains
3878
a pointer to the respective array or object for each recursion depth.
3879
3880
After successful parsing, the value that is passed by reference to the
3881
constructor contains the parsed value.
3882
3883
@tparam BasicJsonType  the JSON type
3884
*/
3885
template<typename BasicJsonType>
3886
class json_sax_dom_parser
3887
{
3888
  public:
3889
    using number_integer_t = typename BasicJsonType::number_integer_t;
3890
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
3891
    using number_float_t = typename BasicJsonType::number_float_t;
3892
    using string_t = typename BasicJsonType::string_t;
3893
3894
    /*!
3895
    @param[in, out] r  reference to a JSON value that is manipulated while
3896
                       parsing
3897
    @param[in] allow_exceptions_  whether parse errors yield exceptions
3898
    */
3899
    explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
3900
        : root(r), allow_exceptions(allow_exceptions_)
258
3901
    {}
3902
3903
    bool null()
120
3904
    {
120
3905
        handle_value(nullptr);
120
3906
        return true;
120
3907
    }
3908
3909
    bool boolean(bool val)
179
3910
    {
179
3911
        handle_value(val);
179
3912
        return true;
179
3913
    }
3914
3915
    bool number_integer(number_integer_t val)
2.69k
3916
    {
2.69k
3917
        handle_value(val);
2.69k
3918
        return true;
2.69k
3919
    }
3920
3921
    bool number_unsigned(number_unsigned_t val)
22.6k
3922
    {
22.6k
3923
        handle_value(val);
22.6k
3924
        return true;
22.6k
3925
    }
3926
3927
    bool number_float(number_float_t val, const string_t&)
16.8k
3928
    {
16.8k
3929
        handle_value(val);
16.8k
3930
        return true;
16.8k
3931
    }
3932
3933
    bool string(string_t& val)
17.9k
3934
    {
17.9k
3935
        handle_value(val);
17.9k
3936
        return true;
17.9k
3937
    }
3938
3939
    bool start_object(std::size_t len)
14.9k
3940
    {
14.9k
3941
        ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
14.9k
3942
14.9k
3943
        if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
0
3944
        {
0
3945
            JSON_THROW(out_of_range::create(408,
0
3946
                                            "excessive object size: " + std::to_string(len)));
0
3947
        }
14.9k
3948
14.9k
3949
        return true;
14.9k
3950
    }
3951
3952
    bool key(string_t& val)
72.4k
3953
    {
72.4k
3954
        // add null at given key and store the reference for later
72.4k
3955
        object_element = &(ref_stack.back()->m_value.object->operator[](val));
72.4k
3956
        return true;
72.4k
3957
    }
3958
3959
    bool end_object()
14.9k
3960
    {
14.9k
3961
        ref_stack.pop_back();
14.9k
3962
        return true;
14.9k
3963
    }
3964
3965
    bool start_array(std::size_t len)
178
3966
    {
178
3967
        ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
178
3968
178
3969
        if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
0
3970
        {
0
3971
            JSON_THROW(out_of_range::create(408,
0
3972
                                            "excessive array size: " + std::to_string(len)));
0
3973
        }
178
3974
178
3975
        return true;
178
3976
    }
3977
3978
    bool end_array()
178
3979
    {
178
3980
        ref_stack.pop_back();
178
3981
        return true;
178
3982
    }
3983
3984
    bool parse_error(std::size_t, const std::string&,
3985
                     const detail::exception& ex)
0
3986
    {
0
3987
        errored = true;
0
3988
        if (allow_exceptions)
0
3989
        {
0
3990
            // determine the proper exception type from the id
0
3991
            switch ((ex.id / 100) % 100)
0
3992
            {
0
3993
                case 1:
0
3994
                    JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
0
3995
                case 4:
0
3996
                    JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
0
3997
                // LCOV_EXCL_START
0
3998
                case 2:
0
3999
                    JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));
0
4000
                case 3:
0
4001
                    JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));
0
4002
                case 5:
0
4003
                    JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));
0
4004
                default:
0
4005
                    assert(false);
0
4006
                    // LCOV_EXCL_STOP
0
4007
            }
0
4008
        }
0
4009
        return false;
0
4010
    }
4011
4012
    constexpr bool is_errored() const
258
4013
    {
258
4014
        return errored;
258
4015
    }
4016
4017
  private:
4018
    /*!
4019
    @invariant If the ref stack is empty, then the passed value will be the new
4020
               root.
4021
    @invariant If the ref stack contains a value, then it is an array or an
4022
               object to which we can add elements
4023
    */
4024
    template<typename Value>
4025
    BasicJsonType* handle_value(Value&& v)
75.4k
4026
    {
75.4k
4027
        if (ref_stack.empty())
258
4028
        {
258
4029
            root = BasicJsonType(std::forward<Value>(v));
258
4030
            return &root;
258
4031
        }
75.4k
4032
        else
75.2k
4033
        {
75.2k
4034
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
75.2k
4035
            if (ref_stack.back()->is_array())
2.81k
4036
            {
2.81k
4037
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
2.81k
4038
                return &(ref_stack.back()->m_value.array->back());
2.81k
4039
            }
75.2k
4040
            else
72.4k
4041
            {
72.4k
4042
                assert(object_element);
72.4k
4043
                *object_element = BasicJsonType(std::forward<Value>(v));
72.4k
4044
                return object_element;
72.4k
4045
            }
75.2k
4046
        }
75.4k
4047
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueINS0_7value_tEEEPSC_OT_
15.0k
4026
    {
15.0k
4027
        if (ref_stack.empty())
258
4028
        {
258
4029
            root = BasicJsonType(std::forward<Value>(v));
258
4030
            return &root;
258
4031
        }
15.0k
4032
        else
14.8k
4033
        {
14.8k
4034
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
14.8k
4035
            if (ref_stack.back()->is_array())
2.81k
4036
            {
2.81k
4037
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
2.81k
4038
                return &(ref_stack.back()->m_value.array->back());
2.81k
4039
            }
14.8k
4040
            else
12.0k
4041
            {
12.0k
4042
                assert(object_element);
12.0k
4043
                *object_element = BasicJsonType(std::forward<Value>(v));
12.0k
4044
                return object_element;
12.0k
4045
            }
14.8k
4046
        }
15.0k
4047
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRdEEPSC_OT_
16.8k
4026
    {
16.8k
4027
        if (ref_stack.empty())
0
4028
        {
0
4029
            root = BasicJsonType(std::forward<Value>(v));
0
4030
            return &root;
0
4031
        }
16.8k
4032
        else
16.8k
4033
        {
16.8k
4034
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
16.8k
4035
            if (ref_stack.back()->is_array())
0
4036
            {
0
4037
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
0
4038
                return &(ref_stack.back()->m_value.array->back());
0
4039
            }
16.8k
4040
            else
16.8k
4041
            {
16.8k
4042
                assert(object_element);
16.8k
4043
                *object_element = BasicJsonType(std::forward<Value>(v));
16.8k
4044
                return object_element;
16.8k
4045
            }
16.8k
4046
        }
16.8k
4047
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRbEEPSC_OT_
179
4026
    {
179
4027
        if (ref_stack.empty())
0
4028
        {
0
4029
            root = BasicJsonType(std::forward<Value>(v));
0
4030
            return &root;
0
4031
        }
179
4032
        else
179
4033
        {
179
4034
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
179
4035
            if (ref_stack.back()->is_array())
0
4036
            {
0
4037
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
0
4038
                return &(ref_stack.back()->m_value.array->back());
0
4039
            }
179
4040
            else
179
4041
            {
179
4042
                assert(object_element);
179
4043
                *object_element = BasicJsonType(std::forward<Value>(v));
179
4044
                return object_element;
179
4045
            }
179
4046
        }
179
4047
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIDnEEPSC_OT_
120
4026
    {
120
4027
        if (ref_stack.empty())
0
4028
        {
0
4029
            root = BasicJsonType(std::forward<Value>(v));
0
4030
            return &root;
0
4031
        }
120
4032
        else
120
4033
        {
120
4034
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
120
4035
            if (ref_stack.back()->is_array())
0
4036
            {
0
4037
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
0
4038
                return &(ref_stack.back()->m_value.array->back());
0
4039
            }
120
4040
            else
120
4041
            {
120
4042
                assert(object_element);
120
4043
                *object_element = BasicJsonType(std::forward<Value>(v));
120
4044
                return object_element;
120
4045
            }
120
4046
        }
120
4047
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRlEEPSC_OT_
2.69k
4026
    {
2.69k
4027
        if (ref_stack.empty())
0
4028
        {
0
4029
            root = BasicJsonType(std::forward<Value>(v));
0
4030
            return &root;
0
4031
        }
2.69k
4032
        else
2.69k
4033
        {
2.69k
4034
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
2.69k
4035
            if (ref_stack.back()->is_array())
0
4036
            {
0
4037
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
0
4038
                return &(ref_stack.back()->m_value.array->back());
0
4039
            }
2.69k
4040
            else
2.69k
4041
            {
2.69k
4042
                assert(object_element);
2.69k
4043
                *object_element = BasicJsonType(std::forward<Value>(v));
2.69k
4044
                return object_element;
2.69k
4045
            }
2.69k
4046
        }
2.69k
4047
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRSA_EEPSC_OT_
17.9k
4026
    {
17.9k
4027
        if (ref_stack.empty())
0
4028
        {
0
4029
            root = BasicJsonType(std::forward<Value>(v));
0
4030
            return &root;
0
4031
        }
17.9k
4032
        else
17.9k
4033
        {
17.9k
4034
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
17.9k
4035
            if (ref_stack.back()->is_array())
0
4036
            {
0
4037
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
0
4038
                return &(ref_stack.back()->m_value.array->back());
0
4039
            }
17.9k
4040
            else
17.9k
4041
            {
17.9k
4042
                assert(object_element);
17.9k
4043
                *object_element = BasicJsonType(std::forward<Value>(v));
17.9k
4044
                return object_element;
17.9k
4045
            }
17.9k
4046
        }
17.9k
4047
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRmEEPSC_OT_
22.6k
4026
    {
22.6k
4027
        if (ref_stack.empty())
0
4028
        {
0
4029
            root = BasicJsonType(std::forward<Value>(v));
0
4030
            return &root;
0
4031
        }
22.6k
4032
        else
22.6k
4033
        {
22.6k
4034
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
22.6k
4035
            if (ref_stack.back()->is_array())
0
4036
            {
0
4037
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
0
4038
                return &(ref_stack.back()->m_value.array->back());
0
4039
            }
22.6k
4040
            else
22.6k
4041
            {
22.6k
4042
                assert(object_element);
22.6k
4043
                *object_element = BasicJsonType(std::forward<Value>(v));
22.6k
4044
                return object_element;
22.6k
4045
            }
22.6k
4046
        }
22.6k
4047
    }
4048
4049
    /// the parsed JSON value
4050
    BasicJsonType& root;
4051
    /// stack to model hierarchy of values
4052
    std::vector<BasicJsonType*> ref_stack;
4053
    /// helper to hold the reference for the next object element
4054
    BasicJsonType* object_element = nullptr;
4055
    /// whether a syntax error occurred
4056
    bool errored = false;
4057
    /// whether to throw exceptions in case of errors
4058
    const bool allow_exceptions = true;
4059
};
4060
4061
template<typename BasicJsonType>
4062
class json_sax_dom_callback_parser
4063
{
4064
  public:
4065
    using number_integer_t = typename BasicJsonType::number_integer_t;
4066
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
4067
    using number_float_t = typename BasicJsonType::number_float_t;
4068
    using string_t = typename BasicJsonType::string_t;
4069
    using parser_callback_t = typename BasicJsonType::parser_callback_t;
4070
    using parse_event_t = typename BasicJsonType::parse_event_t;
4071
4072
    json_sax_dom_callback_parser(BasicJsonType& r,
4073
                                 const parser_callback_t cb,
4074
                                 const bool allow_exceptions_ = true)
4075
        : root(r), callback(cb), allow_exceptions(allow_exceptions_)
0
4076
    {
0
4077
        keep_stack.push_back(true);
0
4078
    }
4079
4080
    bool null()
0
4081
    {
0
4082
        handle_value(nullptr);
0
4083
        return true;
0
4084
    }
4085
4086
    bool boolean(bool val)
0
4087
    {
0
4088
        handle_value(val);
0
4089
        return true;
0
4090
    }
4091
4092
    bool number_integer(number_integer_t val)
0
4093
    {
0
4094
        handle_value(val);
0
4095
        return true;
0
4096
    }
4097
4098
    bool number_unsigned(number_unsigned_t val)
0
4099
    {
0
4100
        handle_value(val);
0
4101
        return true;
0
4102
    }
4103
4104
    bool number_float(number_float_t val, const string_t&)
0
4105
    {
0
4106
        handle_value(val);
0
4107
        return true;
0
4108
    }
4109
4110
    bool string(string_t& val)
0
4111
    {
0
4112
        handle_value(val);
0
4113
        return true;
0
4114
    }
4115
4116
    bool start_object(std::size_t len)
0
4117
    {
0
4118
        // check callback for object start
0
4119
        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
0
4120
        keep_stack.push_back(keep);
0
4121
0
4122
        auto val = handle_value(BasicJsonType::value_t::object, true);
0
4123
        ref_stack.push_back(val.second);
0
4124
0
4125
        // check object limit
0
4126
        if (ref_stack.back())
0
4127
        {
0
4128
            if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
0
4129
            {
0
4130
                JSON_THROW(out_of_range::create(408,
0
4131
                                                "excessive object size: " + std::to_string(len)));
0
4132
            }
0
4133
        }
0
4134
0
4135
        return true;
0
4136
    }
4137
4138
    bool key(string_t& val)
0
4139
    {
0
4140
        BasicJsonType k = BasicJsonType(val);
0
4141
0
4142
        // check callback for key
0
4143
        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
0
4144
        key_keep_stack.push_back(keep);
0
4145
0
4146
        // add discarded value at given key and store the reference for later
0
4147
        if (keep and ref_stack.back())
0
4148
        {
0
4149
            object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
0
4150
        }
0
4151
0
4152
        return true;
0
4153
    }
4154
4155
    bool end_object()
0
4156
    {
0
4157
        if (ref_stack.back())
0
4158
        {
0
4159
            if (not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
0
4160
            {
0
4161
                // discard object
0
4162
                *ref_stack.back() = discarded;
0
4163
            }
0
4164
        }
0
4165
0
4166
        assert(not ref_stack.empty());
0
4167
        assert(not keep_stack.empty());
0
4168
        ref_stack.pop_back();
0
4169
        keep_stack.pop_back();
0
4170
0
4171
        if (not ref_stack.empty() and ref_stack.back())
0
4172
        {
0
4173
            // remove discarded value
0
4174
            if (ref_stack.back()->is_object())
0
4175
            {
0
4176
                for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
0
4177
                {
0
4178
                    if (it->is_discarded())
0
4179
                    {
0
4180
                        ref_stack.back()->erase(it);
0
4181
                        break;
0
4182
                    }
0
4183
                }
0
4184
            }
0
4185
        }
0
4186
0
4187
        return true;
0
4188
    }
4189
4190
    bool start_array(std::size_t len)
0
4191
    {
0
4192
        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
0
4193
        keep_stack.push_back(keep);
0
4194
0
4195
        auto val = handle_value(BasicJsonType::value_t::array, true);
0
4196
        ref_stack.push_back(val.second);
0
4197
0
4198
        // check array limit
0
4199
        if (ref_stack.back())
0
4200
        {
0
4201
            if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
0
4202
            {
0
4203
                JSON_THROW(out_of_range::create(408,
0
4204
                                                "excessive array size: " + std::to_string(len)));
0
4205
            }
0
4206
        }
0
4207
0
4208
        return true;
0
4209
    }
4210
4211
    bool end_array()
0
4212
    {
0
4213
        bool keep = true;
0
4214
0
4215
        if (ref_stack.back())
0
4216
        {
0
4217
            keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
0
4218
            if (not keep)
0
4219
            {
0
4220
                // discard array
0
4221
                *ref_stack.back() = discarded;
0
4222
            }
0
4223
        }
0
4224
0
4225
        assert(not ref_stack.empty());
0
4226
        assert(not keep_stack.empty());
0
4227
        ref_stack.pop_back();
0
4228
        keep_stack.pop_back();
0
4229
0
4230
        // remove discarded value
0
4231
        if (not keep and not ref_stack.empty())
0
4232
        {
0
4233
            if (ref_stack.back()->is_array())
0
4234
            {
0
4235
                ref_stack.back()->m_value.array->pop_back();
0
4236
            }
0
4237
        }
0
4238
0
4239
        return true;
0
4240
    }
4241
4242
    bool parse_error(std::size_t, const std::string&,
4243
                     const detail::exception& ex)
0
4244
    {
0
4245
        errored = true;
0
4246
        if (allow_exceptions)
0
4247
        {
0
4248
            // determine the proper exception type from the id
0
4249
            switch ((ex.id / 100) % 100)
0
4250
            {
0
4251
                case 1:
0
4252
                    JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
0
4253
                case 4:
0
4254
                    JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
0
4255
                // LCOV_EXCL_START
0
4256
                case 2:
0
4257
                    JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));
0
4258
                case 3:
0
4259
                    JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));
0
4260
                case 5:
0
4261
                    JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));
0
4262
                default:
0
4263
                    assert(false);
0
4264
                    // LCOV_EXCL_STOP
0
4265
            }
0
4266
        }
0
4267
        return false;
0
4268
    }
4269
4270
    constexpr bool is_errored() const
0
4271
    {
0
4272
        return errored;
0
4273
    }
4274
4275
  private:
4276
    /*!
4277
    @param[in] v  value to add to the JSON value we build during parsing
4278
    @param[in] skip_callback  whether we should skip calling the callback
4279
               function; this is required after start_array() and
4280
               start_object() SAX events, because otherwise we would call the
4281
               callback function with an empty array or object, respectively.
4282
4283
    @invariant If the ref stack is empty, then the passed value will be the new
4284
               root.
4285
    @invariant If the ref stack contains a value, then it is an array or an
4286
               object to which we can add elements
4287
4288
    @return pair of boolean (whether value should be kept) and pointer (to the
4289
            passed value in the ref_stack hierarchy; nullptr if not kept)
4290
    */
4291
    template<typename Value>
4292
    std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
0
4293
    {
0
4294
        assert(not keep_stack.empty());
0
4295
0
4296
        // do not handle this value if we know it would be added to a discarded
0
4297
        // container
0
4298
        if (not keep_stack.back())
0
4299
        {
0
4300
            return {false, nullptr};
0
4301
        }
0
4302
0
4303
        // create value
0
4304
        auto value = BasicJsonType(std::forward<Value>(v));
0
4305
0
4306
        // check callback
0
4307
        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
0
4308
0
4309
        // do not handle this value if we just learnt it shall be discarded
0
4310
        if (not keep)
0
4311
        {
0
4312
            return {false, nullptr};
0
4313
        }
0
4314
0
4315
        if (ref_stack.empty())
0
4316
        {
0
4317
            root = std::move(value);
0
4318
            return {true, &root};
0
4319
        }
0
4320
        else
0
4321
        {
0
4322
            // skip this value if we already decided to skip the parent
0
4323
            // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
0
4324
            if (not ref_stack.back())
0
4325
            {
0
4326
                return {false, nullptr};
0
4327
            }
0
4328
0
4329
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
0
4330
            if (ref_stack.back()->is_array())
0
4331
            {
0
4332
                ref_stack.back()->m_value.array->push_back(std::move(value));
0
4333
                return {true, &(ref_stack.back()->m_value.array->back())};
0
4334
            }
0
4335
            else
0
4336
            {
0
4337
                // check if we should store an element for the current key
0
4338
                assert(not key_keep_stack.empty());
0
4339
                const bool store_element = key_keep_stack.back();
0
4340
                key_keep_stack.pop_back();
0
4341
0
4342
                if (not store_element)
0
4343
                {
0
4344
                    return {false, nullptr};
0
4345
                }
0
4346
0
4347
                assert(object_element);
0
4348
                *object_element = std::move(value);
0
4349
                return {true, object_element};
0
4350
            }
0
4351
        }
0
4352
    }
_ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRlEESt4pairIbPSC_EOT_b
0
4293
    {
0
4294
        assert(not keep_stack.empty());
0
4295
0
4296
        // do not handle this value if we know it would be added to a discarded
0
4297
        // container
0
4298
        if (not keep_stack.back())
0
4299
        {
0
4300
            return {false, nullptr};
0
4301
        }
0
4302
0
4303
        // create value
0
4304
        auto value = BasicJsonType(std::forward<Value>(v));
0
4305
0
4306
        // check callback
0
4307
        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
0
4308
0
4309
        // do not handle this value if we just learnt it shall be discarded
0
4310
        if (not keep)
0
4311
        {
0
4312
            return {false, nullptr};
0
4313
        }
0
4314
0
4315
        if (ref_stack.empty())
0
4316
        {
0
4317
            root = std::move(value);
0
4318
            return {true, &root};
0
4319
        }
0
4320
        else
0
4321
        {
0
4322
            // skip this value if we already decided to skip the parent
0
4323
            // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
0
4324
            if (not ref_stack.back())
0
4325
            {
0
4326
                return {false, nullptr};
0
4327
            }
0
4328
0
4329
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
0
4330
            if (ref_stack.back()->is_array())
0
4331
            {
0
4332
                ref_stack.back()->m_value.array->push_back(std::move(value));
0
4333
                return {true, &(ref_stack.back()->m_value.array->back())};
0
4334
            }
0
4335
            else
0
4336
            {
0
4337
                // check if we should store an element for the current key
0
4338
                assert(not key_keep_stack.empty());
0
4339
                const bool store_element = key_keep_stack.back();
0
4340
                key_keep_stack.pop_back();
0
4341
0
4342
                if (not store_element)
0
4343
                {
0
4344
                    return {false, nullptr};
0
4345
                }
0
4346
0
4347
                assert(object_element);
0
4348
                *object_element = std::move(value);
0
4349
                return {true, object_element};
0
4350
            }
0
4351
        }
0
4352
    }
_ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueINS0_7value_tEEESt4pairIbPSC_EOT_b
0
4293
    {
0
4294
        assert(not keep_stack.empty());
0
4295
0
4296
        // do not handle this value if we know it would be added to a discarded
0
4297
        // container
0
4298
        if (not keep_stack.back())
0
4299
        {
0
4300
            return {false, nullptr};
0
4301
        }
0
4302
0
4303
        // create value
0
4304
        auto value = BasicJsonType(std::forward<Value>(v));
0
4305
0
4306
        // check callback
0
4307
        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
0
4308
0
4309
        // do not handle this value if we just learnt it shall be discarded
0
4310
        if (not keep)
0
4311
        {
0
4312
            return {false, nullptr};
0
4313
        }
0
4314
0
4315
        if (ref_stack.empty())
0
4316
        {
0
4317
            root = std::move(value);
0
4318
            return {true, &root};
0
4319
        }
0
4320
        else
0
4321
        {
0
4322
            // skip this value if we already decided to skip the parent
0
4323
            // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
0
4324
            if (not ref_stack.back())
0
4325
            {
0
4326
                return {false, nullptr};
0
4327
            }
0
4328
0
4329
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
0
4330
            if (ref_stack.back()->is_array())
0
4331
            {
0
4332
                ref_stack.back()->m_value.array->push_back(std::move(value));
0
4333
                return {true, &(ref_stack.back()->m_value.array->back())};
0
4334
            }
0
4335
            else
0
4336
            {
0
4337
                // check if we should store an element for the current key
0
4338
                assert(not key_keep_stack.empty());
0
4339
                const bool store_element = key_keep_stack.back();
0
4340
                key_keep_stack.pop_back();
0
4341
0
4342
                if (not store_element)
0
4343
                {
0
4344
                    return {false, nullptr};
0
4345
                }
0
4346
0
4347
                assert(object_element);
0
4348
                *object_element = std::move(value);
0
4349
                return {true, object_element};
0
4350
            }
0
4351
        }
0
4352
    }
_ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRdEESt4pairIbPSC_EOT_b
0
4293
    {
0
4294
        assert(not keep_stack.empty());
0
4295
0
4296
        // do not handle this value if we know it would be added to a discarded
0
4297
        // container
0
4298
        if (not keep_stack.back())
0
4299
        {
0
4300
            return {false, nullptr};
0
4301
        }
0
4302
0
4303
        // create value
0
4304
        auto value = BasicJsonType(std::forward<Value>(v));
0
4305
0
4306
        // check callback
0
4307
        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
0
4308
0
4309
        // do not handle this value if we just learnt it shall be discarded
0
4310
        if (not keep)
0
4311
        {
0
4312
            return {false, nullptr};
0
4313
        }
0
4314
0
4315
        if (ref_stack.empty())
0
4316
        {
0
4317
            root = std::move(value);
0
4318
            return {true, &root};
0
4319
        }
0
4320
        else
0
4321
        {
0
4322
            // skip this value if we already decided to skip the parent
0
4323
            // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
0
4324
            if (not ref_stack.back())
0
4325
            {
0
4326
                return {false, nullptr};
0
4327
            }
0
4328
0
4329
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
0
4330
            if (ref_stack.back()->is_array())
0
4331
            {
0
4332
                ref_stack.back()->m_value.array->push_back(std::move(value));
0
4333
                return {true, &(ref_stack.back()->m_value.array->back())};
0
4334
            }
0
4335
            else
0
4336
            {
0
4337
                // check if we should store an element for the current key
0
4338
                assert(not key_keep_stack.empty());
0
4339
                const bool store_element = key_keep_stack.back();
0
4340
                key_keep_stack.pop_back();
0
4341
0
4342
                if (not store_element)
0
4343
                {
0
4344
                    return {false, nullptr};
0
4345
                }
0
4346
0
4347
                assert(object_element);
0
4348
                *object_element = std::move(value);
0
4349
                return {true, object_element};
0
4350
            }
0
4351
        }
0
4352
    }
_ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRbEESt4pairIbPSC_EOT_b
0
4293
    {
0
4294
        assert(not keep_stack.empty());
0
4295
0
4296
        // do not handle this value if we know it would be added to a discarded
0
4297
        // container
0
4298
        if (not keep_stack.back())
0
4299
        {
0
4300
            return {false, nullptr};
0
4301
        }
0
4302
0
4303
        // create value
0
4304
        auto value = BasicJsonType(std::forward<Value>(v));
0
4305
0
4306
        // check callback
0
4307
        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
0
4308
0
4309
        // do not handle this value if we just learnt it shall be discarded
0
4310
        if (not keep)
0
4311
        {
0
4312
            return {false, nullptr};
0
4313
        }
0
4314
0
4315
        if (ref_stack.empty())
0
4316
        {
0
4317
            root = std::move(value);
0
4318
            return {true, &root};
0
4319
        }
0
4320
        else
0
4321
        {
0
4322
            // skip this value if we already decided to skip the parent
0
4323
            // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
0
4324
            if (not ref_stack.back())
0
4325
            {
0
4326
                return {false, nullptr};
0
4327
            }
0
4328
0
4329
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
0
4330
            if (ref_stack.back()->is_array())
0
4331
            {
0
4332
                ref_stack.back()->m_value.array->push_back(std::move(value));
0
4333
                return {true, &(ref_stack.back()->m_value.array->back())};
0
4334
            }
0
4335
            else
0
4336
            {
0
4337
                // check if we should store an element for the current key
0
4338
                assert(not key_keep_stack.empty());
0
4339
                const bool store_element = key_keep_stack.back();
0
4340
                key_keep_stack.pop_back();
0
4341
0
4342
                if (not store_element)
0
4343
                {
0
4344
                    return {false, nullptr};
0
4345
                }
0
4346
0
4347
                assert(object_element);
0
4348
                *object_element = std::move(value);
0
4349
                return {true, object_element};
0
4350
            }
0
4351
        }
0
4352
    }
_ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIDnEESt4pairIbPSC_EOT_b
0
4293
    {
0
4294
        assert(not keep_stack.empty());
0
4295
0
4296
        // do not handle this value if we know it would be added to a discarded
0
4297
        // container
0
4298
        if (not keep_stack.back())
0
4299
        {
0
4300
            return {false, nullptr};
0
4301
        }
0
4302
0
4303
        // create value
0
4304
        auto value = BasicJsonType(std::forward<Value>(v));
0
4305
0
4306
        // check callback
0
4307
        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
0
4308
0
4309
        // do not handle this value if we just learnt it shall be discarded
0
4310
        if (not keep)
0
4311
        {
0
4312
            return {false, nullptr};
0
4313
        }
0
4314
0
4315
        if (ref_stack.empty())
0
4316
        {
0
4317
            root = std::move(value);
0
4318
            return {true, &root};
0
4319
        }
0
4320
        else
0
4321
        {
0
4322
            // skip this value if we already decided to skip the parent
0
4323
            // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
0
4324
            if (not ref_stack.back())
0
4325
            {
0
4326
                return {false, nullptr};
0
4327
            }
0
4328
0
4329
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
0
4330
            if (ref_stack.back()->is_array())
0
4331
            {
0
4332
                ref_stack.back()->m_value.array->push_back(std::move(value));
0
4333
                return {true, &(ref_stack.back()->m_value.array->back())};
0
4334
            }
0
4335
            else
0
4336
            {
0
4337
                // check if we should store an element for the current key
0
4338
                assert(not key_keep_stack.empty());
0
4339
                const bool store_element = key_keep_stack.back();
0
4340
                key_keep_stack.pop_back();
0
4341
0
4342
                if (not store_element)
0
4343
                {
0
4344
                    return {false, nullptr};
0
4345
                }
0
4346
0
4347
                assert(object_element);
0
4348
                *object_element = std::move(value);
0
4349
                return {true, object_element};
0
4350
            }
0
4351
        }
0
4352
    }
_ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRSA_EESt4pairIbPSC_EOT_b
0
4293
    {
0
4294
        assert(not keep_stack.empty());
0
4295
0
4296
        // do not handle this value if we know it would be added to a discarded
0
4297
        // container
0
4298
        if (not keep_stack.back())
0
4299
        {
0
4300
            return {false, nullptr};
0
4301
        }
0
4302
0
4303
        // create value
0
4304
        auto value = BasicJsonType(std::forward<Value>(v));
0
4305
0
4306
        // check callback
0
4307
        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
0
4308
0
4309
        // do not handle this value if we just learnt it shall be discarded
0
4310
        if (not keep)
0
4311
        {
0
4312
            return {false, nullptr};
0
4313
        }
0
4314
0
4315
        if (ref_stack.empty())
0
4316
        {
0
4317
            root = std::move(value);
0
4318
            return {true, &root};
0
4319
        }
0
4320
        else
0
4321
        {
0
4322
            // skip this value if we already decided to skip the parent
0
4323
            // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
0
4324
            if (not ref_stack.back())
0
4325
            {
0
4326
                return {false, nullptr};
0
4327
            }
0
4328
0
4329
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
0
4330
            if (ref_stack.back()->is_array())
0
4331
            {
0
4332
                ref_stack.back()->m_value.array->push_back(std::move(value));
0
4333
                return {true, &(ref_stack.back()->m_value.array->back())};
0
4334
            }
0
4335
            else
0
4336
            {
0
4337
                // check if we should store an element for the current key
0
4338
                assert(not key_keep_stack.empty());
0
4339
                const bool store_element = key_keep_stack.back();
0
4340
                key_keep_stack.pop_back();
0
4341
0
4342
                if (not store_element)
0
4343
                {
0
4344
                    return {false, nullptr};
0
4345
                }
0
4346
0
4347
                assert(object_element);
0
4348
                *object_element = std::move(value);
0
4349
                return {true, object_element};
0
4350
            }
0
4351
        }
0
4352
    }
_ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRmEESt4pairIbPSC_EOT_b
0
4293
    {
0
4294
        assert(not keep_stack.empty());
0
4295
0
4296
        // do not handle this value if we know it would be added to a discarded
0
4297
        // container
0
4298
        if (not keep_stack.back())
0
4299
        {
0
4300
            return {false, nullptr};
0
4301
        }
0
4302
0
4303
        // create value
0
4304
        auto value = BasicJsonType(std::forward<Value>(v));
0
4305
0
4306
        // check callback
0
4307
        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
0
4308
0
4309
        // do not handle this value if we just learnt it shall be discarded
0
4310
        if (not keep)
0
4311
        {
0
4312
            return {false, nullptr};
0
4313
        }
0
4314
0
4315
        if (ref_stack.empty())
0
4316
        {
0
4317
            root = std::move(value);
0
4318
            return {true, &root};
0
4319
        }
0
4320
        else
0
4321
        {
0
4322
            // skip this value if we already decided to skip the parent
0
4323
            // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
0
4324
            if (not ref_stack.back())
0
4325
            {
0
4326
                return {false, nullptr};
0
4327
            }
0
4328
0
4329
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
0
4330
            if (ref_stack.back()->is_array())
0
4331
            {
0
4332
                ref_stack.back()->m_value.array->push_back(std::move(value));
0
4333
                return {true, &(ref_stack.back()->m_value.array->back())};
0
4334
            }
0
4335
            else
0
4336
            {
0
4337
                // check if we should store an element for the current key
0
4338
                assert(not key_keep_stack.empty());
0
4339
                const bool store_element = key_keep_stack.back();
0
4340
                key_keep_stack.pop_back();
0
4341
0
4342
                if (not store_element)
0
4343
                {
0
4344
                    return {false, nullptr};
0
4345
                }
0
4346
0
4347
                assert(object_element);
0
4348
                *object_element = std::move(value);
0
4349
                return {true, object_element};
0
4350
            }
0
4351
        }
0
4352
    }
4353
4354
    /// the parsed JSON value
4355
    BasicJsonType& root;
4356
    /// stack to model hierarchy of values
4357
    std::vector<BasicJsonType*> ref_stack;
4358
    /// stack to manage which values to keep
4359
    std::vector<bool> keep_stack;
4360
    /// stack to manage which object keys to keep
4361
    std::vector<bool> key_keep_stack;
4362
    /// helper to hold the reference for the next object element
4363
    BasicJsonType* object_element = nullptr;
4364
    /// whether a syntax error occurred
4365
    bool errored = false;
4366
    /// callback function
4367
    const parser_callback_t callback = nullptr;
4368
    /// whether to throw exceptions in case of errors
4369
    const bool allow_exceptions = true;
4370
    /// a discarded value for the callback
4371
    BasicJsonType discarded = BasicJsonType::value_t::discarded;
4372
};
4373
4374
template<typename BasicJsonType>
4375
class json_sax_acceptor
4376
{
4377
  public:
4378
    using number_integer_t = typename BasicJsonType::number_integer_t;
4379
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
4380
    using number_float_t = typename BasicJsonType::number_float_t;
4381
    using string_t = typename BasicJsonType::string_t;
4382
4383
    bool null()
4384
    {
4385
        return true;
4386
    }
4387
4388
    bool boolean(bool)
4389
    {
4390
        return true;
4391
    }
4392
4393
    bool number_integer(number_integer_t)
4394
    {
4395
        return true;
4396
    }
4397
4398
    bool number_unsigned(number_unsigned_t)
4399
    {
4400
        return true;
4401
    }
4402
4403
    bool number_float(number_float_t, const string_t&)
4404
    {
4405
        return true;
4406
    }
4407
4408
    bool string(string_t&)
4409
    {
4410
        return true;
4411
    }
4412
4413
    bool start_object(std::size_t = std::size_t(-1))
4414
    {
4415
        return true;
4416
    }
4417
4418
    bool key(string_t&)
4419
    {
4420
        return true;
4421
    }
4422
4423
    bool end_object()
4424
    {
4425
        return true;
4426
    }
4427
4428
    bool start_array(std::size_t = std::size_t(-1))
4429
    {
4430
        return true;
4431
    }
4432
4433
    bool end_array()
4434
    {
4435
        return true;
4436
    }
4437
4438
    bool parse_error(std::size_t, const std::string&, const detail::exception&)
4439
    {
4440
        return false;
4441
    }
4442
};
4443
}
4444
4445
}
4446
4447
// #include <nlohmann/detail/input/lexer.hpp>
4448
4449
// #include <nlohmann/detail/value_t.hpp>
4450
4451
4452
namespace nlohmann
4453
{
4454
namespace detail
4455
{
4456
////////////
4457
// parser //
4458
////////////
4459
4460
/*!
4461
@brief syntax analysis
4462
4463
This class implements a recursive decent parser.
4464
*/
4465
template<typename BasicJsonType>
4466
class parser
4467
{
4468
    using number_integer_t = typename BasicJsonType::number_integer_t;
4469
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
4470
    using number_float_t = typename BasicJsonType::number_float_t;
4471
    using string_t = typename BasicJsonType::string_t;
4472
    using lexer_t = lexer<BasicJsonType>;
4473
    using token_type = typename lexer_t::token_type;
4474
4475
  public:
4476
    enum class parse_event_t : uint8_t
4477
    {
4478
        /// the parser read `{` and started to process a JSON object
4479
        object_start,
4480
        /// the parser read `}` and finished processing a JSON object
4481
        object_end,
4482
        /// the parser read `[` and started to process a JSON array
4483
        array_start,
4484
        /// the parser read `]` and finished processing a JSON array
4485
        array_end,
4486
        /// the parser read a key of a value in an object
4487
        key,
4488
        /// the parser finished reading a JSON value
4489
        value
4490
    };
4491
4492
    using parser_callback_t =
4493
        std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;
4494
4495
    /// a parser reading from an input adapter
4496
    explicit parser(detail::input_adapter_t&& adapter,
4497
                    const parser_callback_t cb = nullptr,
4498
                    const bool allow_exceptions_ = true)
4499
        : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_)
258
4500
    {
258
4501
        // read first token
258
4502
        get_token();
258
4503
    }
4504
4505
    /*!
4506
    @brief public parser interface
4507
4508
    @param[in] strict      whether to expect the last token to be EOF
4509
    @param[in,out] result  parsed JSON value
4510
4511
    @throw parse_error.101 in case of an unexpected token
4512
    @throw parse_error.102 if to_unicode fails or surrogate error
4513
    @throw parse_error.103 if to_unicode fails
4514
    */
4515
    void parse(const bool strict, BasicJsonType& result)
258
4516
    {
258
4517
        if (callback)
0
4518
        {
0
4519
            json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
0
4520
            sax_parse_internal(&sdp);
0
4521
            result.assert_invariant();
0
4522
0
4523
            // in strict mode, input must be completely read
0
4524
            if (strict and (get_token() != token_type::end_of_input))
0
4525
            {
0
4526
                sdp.parse_error(m_lexer.get_position(),
0
4527
                                m_lexer.get_token_string(),
0
4528
                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
0
4529
            }
0
4530
0
4531
            // in case of an error, return discarded value
0
4532
            if (sdp.is_errored())
0
4533
            {
0
4534
                result = value_t::discarded;
0
4535
                return;
0
4536
            }
0
4537
0
4538
            // set top-level value to null if it was discarded by the callback
0
4539
            // function
0
4540
            if (result.is_discarded())
0
4541
            {
0
4542
                result = nullptr;
0
4543
            }
0
4544
        }
258
4545
        else
258
4546
        {
258
4547
            json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
258
4548
            sax_parse_internal(&sdp);
258
4549
            result.assert_invariant();
258
4550
258
4551
            // in strict mode, input must be completely read
258
4552
            if (strict and (get_token() != token_type::end_of_input))
0
4553
            {
0
4554
                sdp.parse_error(m_lexer.get_position(),
0
4555
                                m_lexer.get_token_string(),
0
4556
                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
0
4557
            }
258
4558
258
4559
            // in case of an error, return discarded value
258
4560
            if (sdp.is_errored())
0
4561
            {
0
4562
                result = value_t::discarded;
0
4563
                return;
0
4564
            }
258
4565
        }
258
4566
    }
4567
4568
    /*!
4569
    @brief public accept interface
4570
4571
    @param[in] strict  whether to expect the last token to be EOF
4572
    @return whether the input is a proper JSON text
4573
    */
4574
    bool accept(const bool strict = true)
4575
    {
4576
        json_sax_acceptor<BasicJsonType> sax_acceptor;
4577
        return sax_parse(&sax_acceptor, strict);
4578
    }
4579
4580
    template <typename SAX>
4581
    bool sax_parse(SAX* sax, const bool strict = true)
4582
    {
4583
        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
4584
        const bool result = sax_parse_internal(sax);
4585
4586
        // strict mode: next byte must be EOF
4587
        if (result and strict and (get_token() != token_type::end_of_input))
4588
        {
4589
            return sax->parse_error(m_lexer.get_position(),
4590
                                    m_lexer.get_token_string(),
4591
                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
4592
        }
4593
4594
        return result;
4595
    }
4596
4597
  private:
4598
    template <typename SAX>
4599
    bool sax_parse_internal(SAX* sax)
258
4600
    {
258
4601
        // stack to remember the hieararchy of structured values we are parsing
258
4602
        // true = array; false = object
258
4603
        std::vector<bool> states;
258
4604
        // value to avoid a goto (see comment where set to true)
258
4605
        bool skip_to_state_evaluation = false;
258
4606
90.5k
4607
        while (true)
90.5k
4608
        {
90.5k
4609
            if (not skip_to_state_evaluation)
75.4k
4610
            {
75.4k
4611
                // invariant: get_token() was called before each iteration
60.4k
4612
                switch (last_token)
60.4k
4613
                {
14.9k
4614
                    case token_type::begin_object:
14.9k
4615
                    {
14.9k
4616
                        if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
0
4617
                        {
0
4618
                            return false;
0
4619
                        }
14.9k
4620
14.9k
4621
                        // closing } -> we are done
14.9k
4622
                        if (get_token() == token_type::end_object)
0
4623
                        {
0
4624
                            if (JSON_UNLIKELY(not sax->end_object()))
0
4625
                            {
0
4626
                                return false;
0
4627
                            }
0
4628
                            break;
0
4629
                        }
14.9k
4630
14.9k
4631
                        // parse key
14.9k
4632
                        if (JSON_UNLIKELY(last_token != token_type::value_string))
0
4633
                        {
0
4634
                            return sax->parse_error(m_lexer.get_position(),
0
4635
                                                    m_lexer.get_token_string(),
0
4636
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
0
4637
                        }
14.9k
4638
                        else
14.9k
4639
                        {
14.9k
4640
                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
0
4641
                            {
0
4642
                                return false;
0
4643
                            }
14.9k
4644
                        }
14.9k
4645
14.9k
4646
                        // parse separator (:)
14.9k
4647
                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))
0
4648
                        {
0
4649
                            return sax->parse_error(m_lexer.get_position(),
0
4650
                                                    m_lexer.get_token_string(),
0
4651
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
0
4652
                        }
14.9k
4653
14.9k
4654
                        // remember we are now inside an object
14.9k
4655
                        states.push_back(false);
14.9k
4656
14.9k
4657
                        // parse values
14.9k
4658
                        get_token();
14.9k
4659
                        continue;
14.9k
4660
                    }
14.9k
4661
178
4662
                    case token_type::begin_array:
178
4663
                    {
178
4664
                        if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
0
4665
                        {
0
4666
                            return false;
0
4667
                        }
178
4668
178
4669
                        // closing ] -> we are done
178
4670
                        if (get_token() == token_type::end_array)
58
4671
                        {
58
4672
                            if (JSON_UNLIKELY(not sax->end_array()))
0
4673
                            {
0
4674
                                return false;
0
4675
                            }
58
4676
                            break;
58
4677
                        }
178
4678
178
4679
                        // remember we are now inside an array
120
4680
                        states.push_back(true);
120
4681
120
4682
                        // parse values (no need to call get_token)
120
4683
                        continue;
178
4684
                    }
178
4685
16.8k
4686
                    case token_type::value_float:
16.8k
4687
                    {
16.8k
4688
                        const auto res = m_lexer.get_number_float();
16.8k
4689
16.8k
4690
                        if (JSON_UNLIKELY(not std::isfinite(res)))
0
4691
                        {
0
4692
                            return sax->parse_error(m_lexer.get_position(),
0
4693
                                                    m_lexer.get_token_string(),
0
4694
                                                    out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
0
4695
                        }
16.8k
4696
                        else
16.8k
4697
                        {
16.8k
4698
                            if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
0
4699
                            {
0
4700
                                return false;
0
4701
                            }
16.8k
4702
                            break;
16.8k
4703
                        }
16.8k
4704
                    }
16.8k
4705
0
4706
                    case token_type::literal_false:
0
4707
                    {
0
4708
                        if (JSON_UNLIKELY(not sax->boolean(false)))
0
4709
                        {
0
4710
                            return false;
0
4711
                        }
0
4712
                        break;
0
4713
                    }
0
4714
120
4715
                    case token_type::literal_null:
120
4716
                    {
120
4717
                        if (JSON_UNLIKELY(not sax->null()))
0
4718
                        {
0
4719
                            return false;
0
4720
                        }
120
4721
                        break;
120
4722
                    }
120
4723
179
4724
                    case token_type::literal_true:
179
4725
                    {
179
4726
                        if (JSON_UNLIKELY(not sax->boolean(true)))
0
4727
                        {
0
4728
                            return false;
0
4729
                        }
179
4730
                        break;
179
4731
                    }
179
4732
2.69k
4733
                    case token_type::value_integer:
2.69k
4734
                    {
2.69k
4735
                        if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
0
4736
                        {
0
4737
                            return false;
0
4738
                        }
2.69k
4739
                        break;
2.69k
4740
                    }
2.69k
4741
17.9k
4742
                    case token_type::value_string:
17.9k
4743
                    {
17.9k
4744
                        if (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))
0
4745
                        {
0
4746
                            return false;
0
4747
                        }
17.9k
4748
                        break;
17.9k
4749
                    }
17.9k
4750
22.6k
4751
                    case token_type::value_unsigned:
22.6k
4752
                    {
22.6k
4753
                        if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
0
4754
                        {
0
4755
                            return false;
0
4756
                        }
22.6k
4757
                        break;
22.6k
4758
                    }
22.6k
4759
0
4760
                    case token_type::parse_error:
0
4761
                    {
0
4762
                        // using "uninitialized" to avoid "expected" message
0
4763
                        return sax->parse_error(m_lexer.get_position(),
0
4764
                                                m_lexer.get_token_string(),
0
4765
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized)));
22.6k
4766
                    }
22.6k
4767
0
4768
                    default: // the last token was unexpected
0
4769
                    {
0
4770
                        return sax->parse_error(m_lexer.get_position(),
0
4771
                                                m_lexer.get_token_string(),
0
4772
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value)));
22.6k
4773
                    }
60.4k
4774
                }
75.4k
4775
            }
90.5k
4776
            else
15.0k
4777
            {
15.0k
4778
                skip_to_state_evaluation = false;
15.0k
4779
            }
90.5k
4780
90.5k
4781
            // we reached this line after we successfully parsed a value
75.4k
4782
            if (states.empty())
258
4783
            {
258
4784
                // empty stack: we reached the end of the hieararchy: done
258
4785
                return true;
258
4786
            }
75.4k
4787
            else
75.2k
4788
            {
75.2k
4789
                if (states.back())  // array
2.81k
4790
                {
2.81k
4791
                    // comma -> next value
2.81k
4792
                    if (get_token() == token_type::value_separator)
2.69k
4793
                    {
2.69k
4794
                        // parse a new value
2.69k
4795
                        get_token();
2.69k
4796
                        continue;
2.69k
4797
                    }
2.81k
4798
2.81k
4799
                    // closing ]
120
4800
                    if (JSON_LIKELY(last_token == token_type::end_array))
120
4801
                    {
120
4802
                        if (JSON_UNLIKELY(not sax->end_array()))
0
4803
                        {
0
4804
                            return false;
0
4805
                        }
120
4806
120
4807
                        // We are done with this array. Before we can parse a
120
4808
                        // new value, we need to evaluate the new state first.
120
4809
                        // By setting skip_to_state_evaluation to false, we
120
4810
                        // are effectively jumping to the beginning of this if.
120
4811
                        assert(not states.empty());
120
4812
                        states.pop_back();
120
4813
                        skip_to_state_evaluation = true;
120
4814
                        continue;
120
4815
                    }
120
4816
                    else
0
4817
                    {
0
4818
                        return sax->parse_error(m_lexer.get_position(),
0
4819
                                                m_lexer.get_token_string(),
0
4820
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
0
4821
                    }
120
4822
                }
75.2k
4823
                else  // object
72.4k
4824
                {
72.4k
4825
                    // comma -> next value
72.4k
4826
                    if (get_token() == token_type::value_separator)
57.4k
4827
                    {
57.4k
4828
                        // parse key
57.4k
4829
                        if (JSON_UNLIKELY(get_token() != token_type::value_string))
0
4830
                        {
0
4831
                            return sax->parse_error(m_lexer.get_position(),
0
4832
                                                    m_lexer.get_token_string(),
0
4833
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
0
4834
                        }
57.4k
4835
                        else
57.4k
4836
                        {
57.4k
4837
                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
0
4838
                            {
0
4839
                                return false;
0
4840
                            }
57.4k
4841
                        }
57.4k
4842
57.4k
4843
                        // parse separator (:)
57.4k
4844
                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))
0
4845
                        {
0
4846
                            return sax->parse_error(m_lexer.get_position(),
0
4847
                                                    m_lexer.get_token_string(),
0
4848
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
0
4849
                        }
57.4k
4850
57.4k
4851
                        // parse values
57.4k
4852
                        get_token();
57.4k
4853
                        continue;
57.4k
4854
                    }
72.4k
4855
72.4k
4856
                    // closing }
14.9k
4857
                    if (JSON_LIKELY(last_token == token_type::end_object))
14.9k
4858
                    {
14.9k
4859
                        if (JSON_UNLIKELY(not sax->end_object()))
0
4860
                        {
0
4861
                            return false;
0
4862
                        }
14.9k
4863
14.9k
4864
                        // We are done with this object. Before we can parse a
14.9k
4865
                        // new value, we need to evaluate the new state first.
14.9k
4866
                        // By setting skip_to_state_evaluation to false, we
14.9k
4867
                        // are effectively jumping to the beginning of this if.
14.9k
4868
                        assert(not states.empty());
14.9k
4869
                        states.pop_back();
14.9k
4870
                        skip_to_state_evaluation = true;
14.9k
4871
                        continue;
14.9k
4872
                    }
14.9k
4873
                    else
0
4874
                    {
0
4875
                        return sax->parse_error(m_lexer.get_position(),
0
4876
                                                m_lexer.get_token_string(),
0
4877
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
0
4878
                    }
14.9k
4879
                }
75.2k
4880
            }
75.4k
4881
        }
258
4882
    }
_ZN8nlohmann6detail6parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE18sax_parse_internalINS0_28json_sax_dom_callback_parserISC_EEEEbPT_
0
4600
    {
0
4601
        // stack to remember the hieararchy of structured values we are parsing
0
4602
        // true = array; false = object
0
4603
        std::vector<bool> states;
0
4604
        // value to avoid a goto (see comment where set to true)
0
4605
        bool skip_to_state_evaluation = false;
0
4606
0
4607
        while (true)
0
4608
        {
0
4609
            if (not skip_to_state_evaluation)
0
4610
            {
0
4611
                // invariant: get_token() was called before each iteration
0
4612
                switch (last_token)
0
4613
                {
0
4614
                    case token_type::begin_object:
0
4615
                    {
0
4616
                        if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
0
4617
                        {
0
4618
                            return false;
0
4619
                        }
0
4620
0
4621
                        // closing } -> we are done
0
4622
                        if (get_token() == token_type::end_object)
0
4623
                        {
0
4624
                            if (JSON_UNLIKELY(not sax->end_object()))
0
4625
                            {
0
4626
                                return false;
0
4627
                            }
0
4628
                            break;
0
4629
                        }
0
4630
0
4631
                        // parse key
0
4632
                        if (JSON_UNLIKELY(last_token != token_type::value_string))
0
4633
                        {
0
4634
                            return sax->parse_error(m_lexer.get_position(),
0
4635
                                                    m_lexer.get_token_string(),
0
4636
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
0
4637
                        }
0
4638
                        else
0
4639
                        {
0
4640
                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
0
4641
                            {
0
4642
                                return false;
0
4643
                            }
0
4644
                        }
0
4645
0
4646
                        // parse separator (:)
0
4647
                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))
0
4648
                        {
0
4649
                            return sax->parse_error(m_lexer.get_position(),
0
4650
                                                    m_lexer.get_token_string(),
0
4651
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
0
4652
                        }
0
4653
0
4654
                        // remember we are now inside an object
0
4655
                        states.push_back(false);
0
4656
0
4657
                        // parse values
0
4658
                        get_token();
0
4659
                        continue;
0
4660
                    }
0
4661
0
4662
                    case token_type::begin_array:
0
4663
                    {
0
4664
                        if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
0
4665
                        {
0
4666
                            return false;
0
4667
                        }
0
4668
0
4669
                        // closing ] -> we are done
0
4670
                        if (get_token() == token_type::end_array)
0
4671
                        {
0
4672
                            if (JSON_UNLIKELY(not sax->end_array()))
0
4673
                            {
0
4674
                                return false;
0
4675
                            }
0
4676
                            break;
0
4677
                        }
0
4678
0
4679
                        // remember we are now inside an array
0
4680
                        states.push_back(true);
0
4681
0
4682
                        // parse values (no need to call get_token)
0
4683
                        continue;
0
4684
                    }
0
4685
0
4686
                    case token_type::value_float:
0
4687
                    {
0
4688
                        const auto res = m_lexer.get_number_float();
0
4689
0
4690
                        if (JSON_UNLIKELY(not std::isfinite(res)))
0
4691
                        {
0
4692
                            return sax->parse_error(m_lexer.get_position(),
0
4693
                                                    m_lexer.get_token_string(),
0
4694
                                                    out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
0
4695
                        }
0
4696
                        else
0
4697
                        {
0
4698
                            if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
0
4699
                            {
0
4700
                                return false;
0
4701
                            }
0
4702
                            break;
0
4703
                        }
0
4704
                    }
0
4705
0
4706
                    case token_type::literal_false:
0
4707
                    {
0
4708
                        if (JSON_UNLIKELY(not sax->boolean(false)))
0
4709
                        {
0
4710
                            return false;
0
4711
                        }
0
4712
                        break;
0
4713
                    }
0
4714
0
4715
                    case token_type::literal_null:
0
4716
                    {
0
4717
                        if (JSON_UNLIKELY(not sax->null()))
0
4718
                        {
0
4719
                            return false;
0
4720
                        }
0
4721
                        break;
0
4722
                    }
0
4723
0
4724
                    case token_type::literal_true:
0
4725
                    {
0
4726
                        if (JSON_UNLIKELY(not sax->boolean(true)))
0
4727
                        {
0
4728
                            return false;
0
4729
                        }
0
4730
                        break;
0
4731
                    }
0
4732
0
4733
                    case token_type::value_integer:
0
4734
                    {
0
4735
                        if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
0
4736
                        {
0
4737
                            return false;
0
4738
                        }
0
4739
                        break;
0
4740
                    }
0
4741
0
4742
                    case token_type::value_string:
0
4743
                    {
0
4744
                        if (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))
0
4745
                        {
0
4746
                            return false;
0
4747
                        }
0
4748
                        break;
0
4749
                    }
0
4750
0
4751
                    case token_type::value_unsigned:
0
4752
                    {
0
4753
                        if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
0
4754
                        {
0
4755
                            return false;
0
4756
                        }
0
4757
                        break;
0
4758
                    }
0
4759
0
4760
                    case token_type::parse_error:
0
4761
                    {
0
4762
                        // using "uninitialized" to avoid "expected" message
0
4763
                        return sax->parse_error(m_lexer.get_position(),
0
4764
                                                m_lexer.get_token_string(),
0
4765
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized)));
0
4766
                    }
0
4767
0
4768
                    default: // the last token was unexpected
0
4769
                    {
0
4770
                        return sax->parse_error(m_lexer.get_position(),
0
4771
                                                m_lexer.get_token_string(),
0
4772
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value)));
0
4773
                    }
0
4774
                }
0
4775
            }
0
4776
            else
0
4777
            {
0
4778
                skip_to_state_evaluation = false;
0
4779
            }
0
4780
0
4781
            // we reached this line after we successfully parsed a value
0
4782
            if (states.empty())
0
4783
            {
0
4784
                // empty stack: we reached the end of the hieararchy: done
0
4785
                return true;
0
4786
            }
0
4787
            else
0
4788
            {
0
4789
                if (states.back())  // array
0
4790
                {
0
4791
                    // comma -> next value
0
4792
                    if (get_token() == token_type::value_separator)
0
4793
                    {
0
4794
                        // parse a new value
0
4795
                        get_token();
0
4796
                        continue;
0
4797
                    }
0
4798
0
4799
                    // closing ]
0
4800
                    if (JSON_LIKELY(last_token == token_type::end_array))
0
4801
                    {
0
4802
                        if (JSON_UNLIKELY(not sax->end_array()))
0
4803
                        {
0
4804
                            return false;
0
4805
                        }
0
4806
0
4807
                        // We are done with this array. Before we can parse a
0
4808
                        // new value, we need to evaluate the new state first.
0
4809
                        // By setting skip_to_state_evaluation to false, we
0
4810
                        // are effectively jumping to the beginning of this if.
0
4811
                        assert(not states.empty());
0
4812
                        states.pop_back();
0
4813
                        skip_to_state_evaluation = true;
0
4814
                        continue;
0
4815
                    }
0
4816
                    else
0
4817
                    {
0
4818
                        return sax->parse_error(m_lexer.get_position(),
0
4819
                                                m_lexer.get_token_string(),
0
4820
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
0
4821
                    }
0
4822
                }
0
4823
                else  // object
0
4824
                {
0
4825
                    // comma -> next value
0
4826
                    if (get_token() == token_type::value_separator)
0
4827
                    {
0
4828
                        // parse key
0
4829
                        if (JSON_UNLIKELY(get_token() != token_type::value_string))
0
4830
                        {
0
4831
                            return sax->parse_error(m_lexer.get_position(),
0
4832
                                                    m_lexer.get_token_string(),
0
4833
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
0
4834
                        }
0
4835
                        else
0
4836
                        {
0
4837
                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
0
4838
                            {
0
4839
                                return false;
0
4840
                            }
0
4841
                        }
0
4842
0
4843
                        // parse separator (:)
0
4844
                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))
0
4845
                        {
0
4846
                            return sax->parse_error(m_lexer.get_position(),
0
4847
                                                    m_lexer.get_token_string(),
0
4848
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
0
4849
                        }
0
4850
0
4851
                        // parse values
0
4852
                        get_token();
0
4853
                        continue;
0
4854
                    }
0
4855
0
4856
                    // closing }
0
4857
                    if (JSON_LIKELY(last_token == token_type::end_object))
0
4858
                    {
0
4859
                        if (JSON_UNLIKELY(not sax->end_object()))
0
4860
                        {
0
4861
                            return false;
0
4862
                        }
0
4863
0
4864
                        // We are done with this object. Before we can parse a
0
4865
                        // new value, we need to evaluate the new state first.
0
4866
                        // By setting skip_to_state_evaluation to false, we
0
4867
                        // are effectively jumping to the beginning of this if.
0
4868
                        assert(not states.empty());
0
4869
                        states.pop_back();
0
4870
                        skip_to_state_evaluation = true;
0
4871
                        continue;
0
4872
                    }
0
4873
                    else
0
4874
                    {
0
4875
                        return sax->parse_error(m_lexer.get_position(),
0
4876
                                                m_lexer.get_token_string(),
0
4877
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
0
4878
                    }
0
4879
                }
0
4880
            }
0
4881
        }
0
4882
    }
_ZN8nlohmann6detail6parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE18sax_parse_internalINS0_19json_sax_dom_parserISC_EEEEbPT_
258
4600
    {
258
4601
        // stack to remember the hieararchy of structured values we are parsing
258
4602
        // true = array; false = object
258
4603
        std::vector<bool> states;
258
4604
        // value to avoid a goto (see comment where set to true)
258
4605
        bool skip_to_state_evaluation = false;
258
4606
90.5k
4607
        while (true)
90.5k
4608
        {
90.5k
4609
            if (not skip_to_state_evaluation)
75.4k
4610
            {
75.4k
4611
                // invariant: get_token() was called before each iteration
60.4k
4612
                switch (last_token)
60.4k
4613
                {
14.9k
4614
                    case token_type::begin_object:
14.9k
4615
                    {
14.9k
4616
                        if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
0
4617
                        {
0
4618
                            return false;
0
4619
                        }
14.9k
4620
14.9k
4621
                        // closing } -> we are done
14.9k
4622
                        if (get_token() == token_type::end_object)
0
4623
                        {
0
4624
                            if (JSON_UNLIKELY(not sax->end_object()))
0
4625
                            {
0
4626
                                return false;
0
4627
                            }
0
4628
                            break;
0
4629
                        }
14.9k
4630
14.9k
4631
                        // parse key
14.9k
4632
                        if (JSON_UNLIKELY(last_token != token_type::value_string))
0
4633
                        {
0
4634
                            return sax->parse_error(m_lexer.get_position(),
0
4635
                                                    m_lexer.get_token_string(),
0
4636
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
0
4637
                        }
14.9k
4638
                        else
14.9k
4639
                        {
14.9k
4640
                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
0
4641
                            {
0
4642
                                return false;
0
4643
                            }
14.9k
4644
                        }
14.9k
4645
14.9k
4646
                        // parse separator (:)
14.9k
4647
                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))
0
4648
                        {
0
4649
                            return sax->parse_error(m_lexer.get_position(),
0
4650
                                                    m_lexer.get_token_string(),
0
4651
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
0
4652
                        }
14.9k
4653
14.9k
4654
                        // remember we are now inside an object
14.9k
4655
                        states.push_back(false);
14.9k
4656
14.9k
4657
                        // parse values
14.9k
4658
                        get_token();
14.9k
4659
                        continue;
14.9k
4660
                    }
14.9k
4661
178
4662
                    case token_type::begin_array:
178
4663
                    {
178
4664
                        if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
0
4665
                        {
0
4666
                            return false;
0
4667
                        }
178
4668
178
4669
                        // closing ] -> we are done
178
4670
                        if (get_token() == token_type::end_array)
58
4671
                        {
58
4672
                            if (JSON_UNLIKELY(not sax->end_array()))
0
4673
                            {
0
4674
                                return false;
0
4675
                            }
58
4676
                            break;
58
4677
                        }
178
4678
178
4679
                        // remember we are now inside an array
120
4680
                        states.push_back(true);
120
4681
120
4682
                        // parse values (no need to call get_token)
120
4683
                        continue;
178
4684
                    }
178
4685
16.8k
4686
                    case token_type::value_float:
16.8k
4687
                    {
16.8k
4688
                        const auto res = m_lexer.get_number_float();
16.8k
4689
16.8k
4690
                        if (JSON_UNLIKELY(not std::isfinite(res)))
0
4691
                        {
0
4692
                            return sax->parse_error(m_lexer.get_position(),
0
4693
                                                    m_lexer.get_token_string(),
0
4694
                                                    out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
0
4695
                        }
16.8k
4696
                        else
16.8k
4697
                        {
16.8k
4698
                            if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
0
4699
                            {
0
4700
                                return false;
0
4701
                            }
16.8k
4702
                            break;
16.8k
4703
                        }
16.8k
4704
                    }
16.8k
4705
0
4706
                    case token_type::literal_false:
0
4707
                    {
0
4708
                        if (JSON_UNLIKELY(not sax->boolean(false)))
0
4709
                        {
0
4710
                            return false;
0
4711
                        }
0
4712
                        break;
0
4713
                    }
0
4714
120
4715
                    case token_type::literal_null:
120
4716
                    {
120
4717
                        if (JSON_UNLIKELY(not sax->null()))
0
4718
                        {
0
4719
                            return false;
0
4720
                        }
120
4721
                        break;
120
4722
                    }
120
4723
179
4724
                    case token_type::literal_true:
179
4725
                    {
179
4726
                        if (JSON_UNLIKELY(not sax->boolean(true)))
0
4727
                        {
0
4728
                            return false;
0
4729
                        }
179
4730
                        break;
179
4731
                    }
179
4732
2.69k
4733
                    case token_type::value_integer:
2.69k
4734
                    {
2.69k
4735
                        if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
0
4736
                        {
0
4737
                            return false;
0
4738
                        }
2.69k
4739
                        break;
2.69k
4740
                    }
2.69k
4741
17.9k
4742
                    case token_type::value_string:
17.9k
4743
                    {
17.9k
4744
                        if (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))
0
4745
                        {
0
4746
                            return false;
0
4747
                        }
17.9k
4748
                        break;
17.9k
4749
                    }
17.9k
4750
22.6k
4751
                    case token_type::value_unsigned:
22.6k
4752
                    {
22.6k
4753
                        if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
0
4754
                        {
0
4755
                            return false;
0
4756
                        }
22.6k
4757
                        break;
22.6k
4758
                    }
22.6k
4759
0
4760
                    case token_type::parse_error:
0
4761
                    {
0
4762
                        // using "uninitialized" to avoid "expected" message
0
4763
                        return sax->parse_error(m_lexer.get_position(),
0
4764
                                                m_lexer.get_token_string(),
0
4765
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized)));
22.6k
4766
                    }
22.6k
4767
0
4768
                    default: // the last token was unexpected
0
4769
                    {
0
4770
                        return sax->parse_error(m_lexer.get_position(),
0
4771
                                                m_lexer.get_token_string(),
0
4772
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value)));
22.6k
4773
                    }
60.4k
4774
                }
75.4k
4775
            }
90.5k
4776
            else
15.0k
4777
            {
15.0k
4778
                skip_to_state_evaluation = false;
15.0k
4779
            }
90.5k
4780
90.5k
4781
            // we reached this line after we successfully parsed a value
75.4k
4782
            if (states.empty())
258
4783
            {
258
4784
                // empty stack: we reached the end of the hieararchy: done
258
4785
                return true;
258
4786
            }
75.4k
4787
            else
75.2k
4788
            {
75.2k
4789
                if (states.back())  // array
2.81k
4790
                {
2.81k
4791
                    // comma -> next value
2.81k
4792
                    if (get_token() == token_type::value_separator)
2.69k
4793
                    {
2.69k
4794
                        // parse a new value
2.69k
4795
                        get_token();
2.69k
4796
                        continue;
2.69k
4797
                    }
2.81k
4798
2.81k
4799
                    // closing ]
120
4800
                    if (JSON_LIKELY(last_token == token_type::end_array))
120
4801
                    {
120
4802
                        if (JSON_UNLIKELY(not sax->end_array()))
0
4803
                        {
0
4804
                            return false;
0
4805
                        }
120
4806
120
4807
                        // We are done with this array. Before we can parse a
120
4808
                        // new value, we need to evaluate the new state first.
120
4809
                        // By setting skip_to_state_evaluation to false, we
120
4810
                        // are effectively jumping to the beginning of this if.
120
4811
                        assert(not states.empty());
120
4812
                        states.pop_back();
120
4813
                        skip_to_state_evaluation = true;
120
4814
                        continue;
120
4815
                    }
120
4816
                    else
0
4817
                    {
0
4818
                        return sax->parse_error(m_lexer.get_position(),
0
4819
                                                m_lexer.get_token_string(),
0
4820
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
0
4821
                    }
120
4822
                }
75.2k
4823
                else  // object
72.4k
4824
                {
72.4k
4825
                    // comma -> next value
72.4k
4826
                    if (get_token() == token_type::value_separator)
57.4k
4827
                    {
57.4k
4828
                        // parse key
57.4k
4829
                        if (JSON_UNLIKELY(get_token() != token_type::value_string))
0
4830
                        {
0
4831
                            return sax->parse_error(m_lexer.get_position(),
0
4832
                                                    m_lexer.get_token_string(),
0
4833
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
0
4834
                        }
57.4k
4835
                        else
57.4k
4836
                        {
57.4k
4837
                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
0
4838
                            {
0
4839
                                return false;
0
4840
                            }
57.4k
4841
                        }
57.4k
4842
57.4k
4843
                        // parse separator (:)
57.4k
4844
                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))
0
4845
                        {
0
4846
                            return sax->parse_error(m_lexer.get_position(),
0
4847
                                                    m_lexer.get_token_string(),
0
4848
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
0
4849
                        }
57.4k
4850
57.4k
4851
                        // parse values
57.4k
4852
                        get_token();
57.4k
4853
                        continue;
57.4k
4854
                    }
72.4k
4855
72.4k
4856
                    // closing }
14.9k
4857
                    if (JSON_LIKELY(last_token == token_type::end_object))
14.9k
4858
                    {
14.9k
4859
                        if (JSON_UNLIKELY(not sax->end_object()))
0
4860
                        {
0
4861
                            return false;
0
4862
                        }
14.9k
4863
14.9k
4864
                        // We are done with this object. Before we can parse a
14.9k
4865
                        // new value, we need to evaluate the new state first.
14.9k
4866
                        // By setting skip_to_state_evaluation to false, we
14.9k
4867
                        // are effectively jumping to the beginning of this if.
14.9k
4868
                        assert(not states.empty());
14.9k
4869
                        states.pop_back();
14.9k
4870
                        skip_to_state_evaluation = true;
14.9k
4871
                        continue;
14.9k
4872
                    }
14.9k
4873
                    else
0
4874
                    {
0
4875
                        return sax->parse_error(m_lexer.get_position(),
0
4876
                                                m_lexer.get_token_string(),
0
4877
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
0
4878
                    }
14.9k
4879
                }
75.2k
4880
            }
75.4k
4881
        }
258
4882
    }
4883
4884
    /// get next token from lexer
4885
    token_type get_token()
295k
4886
    {
295k
4887
        return (last_token = m_lexer.scan());
295k
4888
    }
4889
4890
    std::string exception_message(const token_type expected)
0
4891
    {
0
4892
        std::string error_msg = "syntax error - ";
0
4893
        if (last_token == token_type::parse_error)
0
4894
        {
0
4895
            error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" +
0
4896
                         m_lexer.get_token_string() + "'";
0
4897
        }
0
4898
        else
0
4899
        {
0
4900
            error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token));
0
4901
        }
0
4902
0
4903
        if (expected != token_type::uninitialized)
0
4904
        {
0
4905
            error_msg += "; expected " + std::string(lexer_t::token_type_name(expected));
0
4906
        }
0
4907
0
4908
        return error_msg;
0
4909
    }
4910
4911
  private:
4912
    /// callback function
4913
    const parser_callback_t callback = nullptr;
4914
    /// the type of the last read token
4915
    token_type last_token = token_type::uninitialized;
4916
    /// the lexer
4917
    lexer_t m_lexer;
4918
    /// whether to throw exceptions in case of errors
4919
    const bool allow_exceptions = true;
4920
};
4921
}
4922
}
4923
4924
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
4925
4926
4927
#include <cstddef> // ptrdiff_t
4928
#include <limits>  // numeric_limits
4929
4930
namespace nlohmann
4931
{
4932
namespace detail
4933
{
4934
/*
4935
@brief an iterator for primitive JSON types
4936
4937
This class models an iterator for primitive JSON types (boolean, number,
4938
string). It's only purpose is to allow the iterator/const_iterator classes
4939
to "iterate" over primitive values. Internally, the iterator is modeled by
4940
a `difference_type` variable. Value begin_value (`0`) models the begin,
4941
end_value (`1`) models past the end.
4942
*/
4943
class primitive_iterator_t
4944
{
4945
  private:
4946
    using difference_type = std::ptrdiff_t;
4947
    static constexpr difference_type begin_value = 0;
4948
    static constexpr difference_type end_value = begin_value + 1;
4949
4950
    /// iterator as signed integer type
4951
    difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();
4952
4953
  public:
4954
    constexpr difference_type get_value() const noexcept
0
4955
    {
0
4956
        return m_it;
0
4957
    }
4958
4959
    /// set iterator to a defined beginning
4960
    void set_begin() noexcept
0
4961
    {
0
4962
        m_it = begin_value;
0
4963
    }
4964
4965
    /// set iterator to a defined past the end
4966
    void set_end() noexcept
2
4967
    {
2
4968
        m_it = end_value;
2
4969
    }
4970
4971
    /// return whether the iterator can be dereferenced
4972
    constexpr bool is_begin() const noexcept
0
4973
    {
0
4974
        return m_it == begin_value;
0
4975
    }
4976
4977
    /// return whether the iterator is at end
4978
    constexpr bool is_end() const noexcept
0
4979
    {
0
4980
        return m_it == end_value;
0
4981
    }
4982
4983
    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
1
4984
    {
1
4985
        return lhs.m_it == rhs.m_it;
1
4986
    }
4987
4988
    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
4989
    {
4990
        return lhs.m_it < rhs.m_it;
4991
    }
4992
4993
    primitive_iterator_t operator+(difference_type n) noexcept
0
4994
    {
0
4995
        auto result = *this;
0
4996
        result += n;
0
4997
        return result;
0
4998
    }
4999
5000
    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
5001
    {
5002
        return lhs.m_it - rhs.m_it;
5003
    }
5004
5005
    primitive_iterator_t& operator++() noexcept
0
5006
    {
0
5007
        ++m_it;
0
5008
        return *this;
0
5009
    }
5010
5011
    primitive_iterator_t const operator++(int) noexcept
0
5012
    {
0
5013
        auto result = *this;
0
5014
        ++m_it;
0
5015
        return result;
0
5016
    }
5017
5018
    primitive_iterator_t& operator--() noexcept
0
5019
    {
0
5020
        --m_it;
0
5021
        return *this;
0
5022
    }
5023
5024
    primitive_iterator_t const operator--(int) noexcept
0
5025
    {
0
5026
        auto result = *this;
0
5027
        --m_it;
0
5028
        return result;
0
5029
    }
5030
5031
    primitive_iterator_t& operator+=(difference_type n) noexcept
0
5032
    {
0
5033
        m_it += n;
0
5034
        return *this;
0
5035
    }
5036
5037
    primitive_iterator_t& operator-=(difference_type n) noexcept
0
5038
    {
0
5039
        m_it -= n;
0
5040
        return *this;
0
5041
    }
5042
};
5043
}
5044
}
5045
5046
// #include <nlohmann/detail/iterators/internal_iterator.hpp>
5047
5048
5049
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
5050
5051
5052
namespace nlohmann
5053
{
5054
namespace detail
5055
{
5056
/*!
5057
@brief an iterator value
5058
5059
@note This structure could easily be a union, but MSVC currently does not allow
5060
unions members with complex constructors, see https://github.com/nlohmann/json/pull/105.
5061
*/
5062
template<typename BasicJsonType> struct internal_iterator
5063
{
5064
    /// iterator for JSON objects
5065
    typename BasicJsonType::object_t::iterator object_iterator {};
5066
    /// iterator for JSON arrays
5067
    typename BasicJsonType::array_t::iterator array_iterator {};
5068
    /// generic iterator for all other types
5069
    primitive_iterator_t primitive_iterator {};
5070
};
5071
}
5072
}
5073
5074
// #include <nlohmann/detail/iterators/iter_impl.hpp>
5075
5076
5077
#include <ciso646> // not
5078
#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
5079
#include <type_traits> // conditional, is_const, remove_const
5080
5081
// #include <nlohmann/detail/exceptions.hpp>
5082
5083
// #include <nlohmann/detail/iterators/internal_iterator.hpp>
5084
5085
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
5086
5087
// #include <nlohmann/detail/macro_scope.hpp>
5088
5089
// #include <nlohmann/detail/meta/cpp_future.hpp>
5090
5091
// #include <nlohmann/detail/value_t.hpp>
5092
5093
5094
namespace nlohmann
5095
{
5096
namespace detail
5097
{
5098
// forward declare, to be able to friend it later on
5099
template<typename IteratorType> class iteration_proxy;
5100
5101
/*!
5102
@brief a template for a bidirectional iterator for the @ref basic_json class
5103
5104
This class implements a both iterators (iterator and const_iterator) for the
5105
@ref basic_json class.
5106
5107
@note An iterator is called *initialized* when a pointer to a JSON value has
5108
      been set (e.g., by a constructor or a copy assignment). If the iterator is
5109
      default-constructed, it is *uninitialized* and most methods are undefined.
5110
      **The library uses assertions to detect calls on uninitialized iterators.**
5111
5112
@requirement The class satisfies the following concept requirements:
5113
-
5114
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
5115
  The iterator that can be moved can be moved in both directions (i.e.
5116
  incremented and decremented).
5117
5118
@since version 1.0.0, simplified in version 2.0.9, change to bidirectional
5119
       iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
5120
*/
5121
template<typename BasicJsonType>
5122
class iter_impl
5123
{
5124
    /// allow basic_json to access private members
5125
    friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
5126
    friend BasicJsonType;
5127
    friend iteration_proxy<iter_impl>;
5128
5129
    using object_t = typename BasicJsonType::object_t;
5130
    using array_t = typename BasicJsonType::array_t;
5131
    // make sure BasicJsonType is basic_json or const basic_json
5132
    static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
5133
                  "iter_impl only accepts (const) basic_json");
5134
5135
  public:
5136
5137
    /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
5138
    /// The C++ Standard has never required user-defined iterators to derive from std::iterator.
5139
    /// A user-defined iterator should provide publicly accessible typedefs named
5140
    /// iterator_category, value_type, difference_type, pointer, and reference.
5141
    /// Note that value_type is required to be non-const, even for constant iterators.
5142
    using iterator_category = std::bidirectional_iterator_tag;
5143
5144
    /// the type of the values when the iterator is dereferenced
5145
    using value_type = typename BasicJsonType::value_type;
5146
    /// a type to represent differences between iterators
5147
    using difference_type = typename BasicJsonType::difference_type;
5148
    /// defines a pointer to the type iterated over (value_type)
5149
    using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
5150
          typename BasicJsonType::const_pointer,
5151
          typename BasicJsonType::pointer>::type;
5152
    /// defines a reference to the type iterated over (value_type)
5153
    using reference =
5154
        typename std::conditional<std::is_const<BasicJsonType>::value,
5155
        typename BasicJsonType::const_reference,
5156
        typename BasicJsonType::reference>::type;
5157
5158
    /// default constructor
5159
    iter_impl() = default;
5160
5161
    /*!
5162
    @brief constructor for a given JSON instance
5163
    @param[in] object  pointer to a JSON object for this iterator
5164
    @pre object != nullptr
5165
    @post The iterator is initialized; i.e. `m_object != nullptr`.
5166
    */
5167
    explicit iter_impl(pointer object) noexcept : m_object(object)
750
5168
    {
750
5169
        assert(m_object != nullptr);
750
5170
750
5171
        switch (m_object->m_type)
750
5172
        {
732
5173
            case value_t::object:
732
5174
            {
732
5175
                m_it.object_iterator = typename object_t::iterator();
732
5176
                break;
732
5177
            }
732
5178
16
5179
            case value_t::array:
16
5180
            {
16
5181
                m_it.array_iterator = typename array_t::iterator();
16
5182
                break;
732
5183
            }
732
5184
2
5185
            default:
2
5186
            {
2
5187
                m_it.primitive_iterator = primitive_iterator_t();
2
5188
                break;
732
5189
            }
750
5190
        }
750
5191
    }
5192
5193
    /*!
5194
    @note The conventional copy constructor and copy assignment are implicitly
5195
          defined. Combined with the following converting constructor and
5196
          assignment, they support: (1) copy from iterator to iterator, (2)
5197
          copy from const iterator to const iterator, and (3) conversion from
5198
          iterator to const iterator. However conversion from const iterator
5199
          to iterator is not defined.
5200
    */
5201
5202
    /*!
5203
    @brief converting constructor
5204
    @param[in] other  non-const iterator to copy from
5205
    @note It is not checked whether @a other is initialized.
5206
    */
5207
    iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
0
5208
        : m_object(other.m_object), m_it(other.m_it) {}
5209
5210
    /*!
5211
    @brief converting assignment
5212
    @param[in,out] other  non-const iterator to copy from
5213
    @return const/non-const iterator
5214
    @note It is not checked whether @a other is initialized.
5215
    */
5216
    iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
5217
    {
5218
        m_object = other.m_object;
5219
        m_it = other.m_it;
5220
        return *this;
5221
    }
5222
5223
  private:
5224
    /*!
5225
    @brief set the iterator to the first value
5226
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5227
    */
5228
    void set_begin() noexcept
170
5229
    {
170
5230
        assert(m_object != nullptr);
170
5231
170
5232
        switch (m_object->m_type)
170
5233
        {
162
5234
            case value_t::object:
162
5235
            {
162
5236
                m_it.object_iterator = m_object->m_value.object->begin();
162
5237
                break;
162
5238
            }
162
5239
8
5240
            case value_t::array:
8
5241
            {
8
5242
                m_it.array_iterator = m_object->m_value.array->begin();
8
5243
                break;
162
5244
            }
162
5245
0
5246
            case value_t::null:
0
5247
            {
0
5248
                // set to end so begin()==end() is true: null is empty
0
5249
                m_it.primitive_iterator.set_end();
0
5250
                break;
162
5251
            }
162
5252
0
5253
            default:
0
5254
            {
0
5255
                m_it.primitive_iterator.set_begin();
0
5256
                break;
162
5257
            }
170
5258
        }
170
5259
    }
5260
5261
    /*!
5262
    @brief set the iterator past the last value
5263
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5264
    */
5265
    void set_end() noexcept
580
5266
    {
580
5267
        assert(m_object != nullptr);
580
5268
580
5269
        switch (m_object->m_type)
580
5270
        {
570
5271
            case value_t::object:
570
5272
            {
570
5273
                m_it.object_iterator = m_object->m_value.object->end();
570
5274
                break;
570
5275
            }
570
5276
8
5277
            case value_t::array:
8
5278
            {
8
5279
                m_it.array_iterator = m_object->m_value.array->end();
8
5280
                break;
570
5281
            }
570
5282
2
5283
            default:
2
5284
            {
2
5285
                m_it.primitive_iterator.set_end();
2
5286
                break;
570
5287
            }
580
5288
        }
580
5289
    }
5290
5291
  public:
5292
    /*!
5293
    @brief return a reference to the value pointed to by the iterator
5294
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5295
    */
5296
    reference operator*() const
531
5297
    {
531
5298
        assert(m_object != nullptr);
531
5299
0
5300
        switch (m_object->m_type)
0
5301
        {
385
5302
            case value_t::object:
385
5303
            {
385
5304
                assert(m_it.object_iterator != m_object->m_value.object->end());
385
5305
                return m_it.object_iterator->second;
385
5306
            }
385
5307
146
5308
            case value_t::array:
146
5309
            {
146
5310
                assert(m_it.array_iterator != m_object->m_value.array->end());
146
5311
                return *m_it.array_iterator;
385
5312
            }
385
5313
0
5314
            case value_t::null:
0
5315
                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
385
5316
0
5317
            default:
0
5318
            {
0
5319
                if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
0
5320
                {
0
5321
                    return *m_object;
0
5322
                }
0
5323
0
5324
                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
0
5325
            }
0
5326
        }
531
5327
    }
5328
5329
    /*!
5330
    @brief dereference the iterator
5331
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5332
    */
5333
    pointer operator->() const
0
5334
    {
0
5335
        assert(m_object != nullptr);
0
5336
0
5337
        switch (m_object->m_type)
0
5338
        {
0
5339
            case value_t::object:
0
5340
            {
0
5341
                assert(m_it.object_iterator != m_object->m_value.object->end());
0
5342
                return &(m_it.object_iterator->second);
0
5343
            }
0
5344
0
5345
            case value_t::array:
0
5346
            {
0
5347
                assert(m_it.array_iterator != m_object->m_value.array->end());
0
5348
                return &*m_it.array_iterator;
0
5349
            }
0
5350
0
5351
            default:
0
5352
            {
0
5353
                if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
0
5354
                {
0
5355
                    return m_object;
0
5356
                }
0
5357
0
5358
                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
0
5359
            }
0
5360
        }
0
5361
    }
5362
5363
    /*!
5364
    @brief post-increment (it++)
5365
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5366
    */
5367
    iter_impl const operator++(int)
5368
    {
5369
        auto result = *this;
5370
        ++(*this);
5371
        return result;
5372
    }
5373
5374
    /*!
5375
    @brief pre-increment (++it)
5376
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5377
    */
5378
    iter_impl& operator++()
526
5379
    {
526
5380
        assert(m_object != nullptr);
526
5381
526
5382
        switch (m_object->m_type)
526
5383
        {
380
5384
            case value_t::object:
380
5385
            {
380
5386
                std::advance(m_it.object_iterator, 1);
380
5387
                break;
380
5388
            }
380
5389
146
5390
            case value_t::array:
146
5391
            {
146
5392
                std::advance(m_it.array_iterator, 1);
146
5393
                break;
380
5394
            }
380
5395
0
5396
            default:
0
5397
            {
0
5398
                ++m_it.primitive_iterator;
0
5399
                break;
380
5400
            }
526
5401
        }
526
5402
526
5403
        return *this;
526
5404
    }
5405
5406
    /*!
5407
    @brief post-decrement (it--)
5408
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5409
    */
5410
    iter_impl const operator--(int)
5411
    {
5412
        auto result = *this;
5413
        --(*this);
5414
        return result;
5415
    }
5416
5417
    /*!
5418
    @brief pre-decrement (--it)
5419
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5420
    */
5421
    iter_impl& operator--()
5422
    {
5423
        assert(m_object != nullptr);
5424
5425
        switch (m_object->m_type)
5426
        {
5427
            case value_t::object:
5428
            {
5429
                std::advance(m_it.object_iterator, -1);
5430
                break;
5431
            }
5432
5433
            case value_t::array:
5434
            {
5435
                std::advance(m_it.array_iterator, -1);
5436
                break;
5437
            }
5438
5439
            default:
5440
            {
5441
                --m_it.primitive_iterator;
5442
                break;
5443
            }
5444
        }
5445
5446
        return *this;
5447
    }
5448
5449
    /*!
5450
    @brief  comparison: equal
5451
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5452
    */
5453
    bool operator==(const iter_impl& other) const
711
5454
    {
711
5455
        // if objects are not the same, the comparison is undefined
711
5456
        if (JSON_UNLIKELY(m_object != other.m_object))
0
5457
        {
0
5458
            JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
0
5459
        }
711
5460
711
5461
        assert(m_object != nullptr);
711
5462
0
5463
        switch (m_object->m_type)
0
5464
        {
556
5465
            case value_t::object:
556
5466
                return (m_it.object_iterator == other.m_it.object_iterator);
556
5467
154
5468
            case value_t::array:
154
5469
                return (m_it.array_iterator == other.m_it.array_iterator);
556
5470
1
5471
            default:
1
5472
                return (m_it.primitive_iterator == other.m_it.primitive_iterator);
0
5473
        }
711
5474
    }
5475
5476
    /*!
5477
    @brief  comparison: not equal
5478
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5479
    */
5480
    bool operator!=(const iter_impl& other) const
711
5481
    {
711
5482
        return not operator==(other);
711
5483
    }
5484
5485
    /*!
5486
    @brief  comparison: smaller
5487
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5488
    */
5489
    bool operator<(const iter_impl& other) const
5490
    {
5491
        // if objects are not the same, the comparison is undefined
5492
        if (JSON_UNLIKELY(m_object != other.m_object))
5493
        {
5494
            JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
5495
        }
5496
5497
        assert(m_object != nullptr);
5498
5499
        switch (m_object->m_type)
5500
        {
5501
            case value_t::object:
5502
                JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators"));
5503
5504
            case value_t::array:
5505
                return (m_it.array_iterator < other.m_it.array_iterator);
5506
5507
            default:
5508
                return (m_it.primitive_iterator < other.m_it.primitive_iterator);
5509
        }
5510
    }
5511
5512
    /*!
5513
    @brief  comparison: less than or equal
5514
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5515
    */
5516
    bool operator<=(const iter_impl& other) const
5517
    {
5518
        return not other.operator < (*this);
5519
    }
5520
5521
    /*!
5522
    @brief  comparison: greater than
5523
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5524
    */
5525
    bool operator>(const iter_impl& other) const
5526
    {
5527
        return not operator<=(other);
5528
    }
5529
5530
    /*!
5531
    @brief  comparison: greater than or equal
5532
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5533
    */
5534
    bool operator>=(const iter_impl& other) const
5535
    {
5536
        return not operator<(other);
5537
    }
5538
5539
    /*!
5540
    @brief  add to iterator
5541
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5542
    */
5543
    iter_impl& operator+=(difference_type i)
5544
    {
5545
        assert(m_object != nullptr);
5546
5547
        switch (m_object->m_type)
5548
        {
5549
            case value_t::object:
5550
                JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
5551
5552
            case value_t::array:
5553
            {
5554
                std::advance(m_it.array_iterator, i);
5555
                break;
5556
            }
5557
5558
            default:
5559
            {
5560
                m_it.primitive_iterator += i;
5561
                break;
5562
            }
5563
        }
5564
5565
        return *this;
5566
    }
5567
5568
    /*!
5569
    @brief  subtract from iterator
5570
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5571
    */
5572
    iter_impl& operator-=(difference_type i)
5573
    {
5574
        return operator+=(-i);
5575
    }
5576
5577
    /*!
5578
    @brief  add to iterator
5579
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5580
    */
5581
    iter_impl operator+(difference_type i) const
5582
    {
5583
        auto result = *this;
5584
        result += i;
5585
        return result;
5586
    }
5587
5588
    /*!
5589
    @brief  addition of distance and iterator
5590
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5591
    */
5592
    friend iter_impl operator+(difference_type i, const iter_impl& it)
5593
    {
5594
        auto result = it;
5595
        result += i;
5596
        return result;
5597
    }
5598
5599
    /*!
5600
    @brief  subtract from iterator
5601
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5602
    */
5603
    iter_impl operator-(difference_type i) const
5604
    {
5605
        auto result = *this;
5606
        result -= i;
5607
        return result;
5608
    }
5609
5610
    /*!
5611
    @brief  return difference
5612
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5613
    */
5614
    difference_type operator-(const iter_impl& other) const
5615
    {
5616
        assert(m_object != nullptr);
5617
5618
        switch (m_object->m_type)
5619
        {
5620
            case value_t::object:
5621
                JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
5622
5623
            case value_t::array:
5624
                return m_it.array_iterator - other.m_it.array_iterator;
5625
5626
            default:
5627
                return m_it.primitive_iterator - other.m_it.primitive_iterator;
5628
        }
5629
    }
5630
5631
    /*!
5632
    @brief  access to successor
5633
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5634
    */
5635
    reference operator[](difference_type n) const
5636
    {
5637
        assert(m_object != nullptr);
5638
5639
        switch (m_object->m_type)
5640
        {
5641
            case value_t::object:
5642
                JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators"));
5643
5644
            case value_t::array:
5645
                return *std::next(m_it.array_iterator, n);
5646
5647
            case value_t::null:
5648
                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
5649
5650
            default:
5651
            {
5652
                if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n))
5653
                {
5654
                    return *m_object;
5655
                }
5656
5657
                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
5658
            }
5659
        }
5660
    }
5661
5662
    /*!
5663
    @brief  return the key of an object iterator
5664
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5665
    */
5666
    const typename object_t::key_type& key() const
0
5667
    {
0
5668
        assert(m_object != nullptr);
0
5669
0
5670
        if (JSON_LIKELY(m_object->is_object()))
0
5671
        {
0
5672
            return m_it.object_iterator->first;
0
5673
        }
0
5674
0
5675
        JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators"));
0
5676
    }
5677
5678
    /*!
5679
    @brief  return the value of an iterator
5680
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5681
    */
5682
    reference value() const
385
5683
    {
385
5684
        return operator*();
385
5685
    }
5686
5687
  private:
5688
    /// associated JSON instance
5689
    pointer m_object = nullptr;
5690
    /// the actual iterator of the associated instance
5691
    internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it;
5692
};
5693
}
5694
}
5695
5696
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
5697
5698
// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
5699
5700
5701
#include <cstddef> // ptrdiff_t
5702
#include <iterator> // reverse_iterator
5703
#include <utility> // declval
5704
5705
namespace nlohmann
5706
{
5707
namespace detail
5708
{
5709
//////////////////////
5710
// reverse_iterator //
5711
//////////////////////
5712
5713
/*!
5714
@brief a template for a reverse iterator class
5715
5716
@tparam Base the base iterator type to reverse. Valid types are @ref
5717
iterator (to create @ref reverse_iterator) and @ref const_iterator (to
5718
create @ref const_reverse_iterator).
5719
5720
@requirement The class satisfies the following concept requirements:
5721
-
5722
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
5723
  The iterator that can be moved can be moved in both directions (i.e.
5724
  incremented and decremented).
5725
- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):
5726
  It is possible to write to the pointed-to element (only if @a Base is
5727
  @ref iterator).
5728
5729
@since version 1.0.0
5730
*/
5731
template<typename Base>
5732
class json_reverse_iterator : public std::reverse_iterator<Base>
5733
{
5734
  public:
5735
    using difference_type = std::ptrdiff_t;
5736
    /// shortcut to the reverse iterator adapter
5737
    using base_iterator = std::reverse_iterator<Base>;
5738
    /// the reference type for the pointed-to element
5739
    using reference = typename Base::reference;
5740
5741
    /// create reverse iterator from iterator
5742
    explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
5743
        : base_iterator(it) {}
5744
5745
    /// create reverse iterator from base class
5746
    explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
5747
5748
    /// post-increment (it++)
5749
    json_reverse_iterator const operator++(int)
5750
    {
5751
        return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
5752
    }
5753
5754
    /// pre-increment (++it)
5755
    json_reverse_iterator& operator++()
5756
    {
5757
        return static_cast<json_reverse_iterator&>(base_iterator::operator++());
5758
    }
5759
5760
    /// post-decrement (it--)
5761
    json_reverse_iterator const operator--(int)
5762
    {
5763
        return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
5764
    }
5765
5766
    /// pre-decrement (--it)
5767
    json_reverse_iterator& operator--()
5768
    {
5769
        return static_cast<json_reverse_iterator&>(base_iterator::operator--());
5770
    }
5771
5772
    /// add to iterator
5773
    json_reverse_iterator& operator+=(difference_type i)
5774
    {
5775
        return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));
5776
    }
5777
5778
    /// add to iterator
5779
    json_reverse_iterator operator+(difference_type i) const
5780
    {
5781
        return static_cast<json_reverse_iterator>(base_iterator::operator+(i));
5782
    }
5783
5784
    /// subtract from iterator
5785
    json_reverse_iterator operator-(difference_type i) const
5786
    {
5787
        return static_cast<json_reverse_iterator>(base_iterator::operator-(i));
5788
    }
5789
5790
    /// return difference
5791
    difference_type operator-(const json_reverse_iterator& other) const
5792
    {
5793
        return base_iterator(*this) - base_iterator(other);
5794
    }
5795
5796
    /// access to successor
5797
    reference operator[](difference_type n) const
5798
    {
5799
        return *(this->operator+(n));
5800
    }
5801
5802
    /// return the key of an object iterator
5803
    auto key() const -> decltype(std::declval<Base>().key())
5804
    {
5805
        auto it = --this->base();
5806
        return it.key();
5807
    }
5808
5809
    /// return the value of an iterator
5810
    reference value() const
5811
    {
5812
        auto it = --this->base();
5813
        return it.operator * ();
5814
    }
5815
};
5816
}
5817
}
5818
5819
// #include <nlohmann/detail/output/output_adapters.hpp>
5820
5821
5822
#include <algorithm> // copy
5823
#include <cstddef> // size_t
5824
#include <ios> // streamsize
5825
#include <iterator> // back_inserter
5826
#include <memory> // shared_ptr, make_shared
5827
#include <ostream> // basic_ostream
5828
#include <string> // basic_string
5829
#include <vector> // vector
5830
5831
namespace nlohmann
5832
{
5833
namespace detail
5834
{
5835
/// abstract output adapter interface
5836
template<typename CharType> struct output_adapter_protocol
5837
{
5838
    virtual void write_character(CharType c) = 0;
5839
    virtual void write_characters(const CharType* s, std::size_t length) = 0;
54
5840
    virtual ~output_adapter_protocol() = default;
5841
};
5842
5843
/// a type to simplify interfaces
5844
template<typename CharType>
5845
using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
5846
5847
/// output adapter for byte vectors
5848
template<typename CharType>
5849
class output_vector_adapter : public output_adapter_protocol<CharType>
5850
{
5851
  public:
5852
    explicit output_vector_adapter(std::vector<CharType>& vec) : v(vec) {}
5853
5854
    void write_character(CharType c) override
5855
    {
5856
        v.push_back(c);
5857
    }
5858
5859
    void write_characters(const CharType* s, std::size_t length) override
5860
    {
5861
        std::copy(s, s + length, std::back_inserter(v));
5862
    }
5863
5864
  private:
5865
    std::vector<CharType>& v;
5866
};
5867
5868
/// output adapter for output streams
5869
template<typename CharType>
5870
class output_stream_adapter : public output_adapter_protocol<CharType>
5871
{
5872
  public:
39
5873
    explicit output_stream_adapter(std::basic_ostream<CharType>& s) : stream(s) {}
5874
5875
    void write_character(CharType c) override
3.16k
5876
    {
3.16k
5877
        stream.put(c);
3.16k
5878
    }
5879
5880
    void write_characters(const CharType* s, std::size_t length) override
4.55k
5881
    {
4.55k
5882
        stream.write(s, static_cast<std::streamsize>(length));
4.55k
5883
    }
5884
5885
  private:
5886
    std::basic_ostream<CharType>& stream;
5887
};
5888
5889
/// output adapter for basic_string
5890
template<typename CharType, typename StringType = std::basic_string<CharType>>
5891
class output_string_adapter : public output_adapter_protocol<CharType>
5892
{
5893
  public:
15
5894
    explicit output_string_adapter(StringType& s) : str(s) {}
5895
5896
    void write_character(CharType c) override
101
5897
    {
101
5898
        str.push_back(c);
101
5899
    }
5900
5901
    void write_characters(const CharType* s, std::size_t length) override
235
5902
    {
235
5903
        str.append(s, length);
235
5904
    }
5905
5906
  private:
5907
    StringType& str;
5908
};
5909
5910
template<typename CharType, typename StringType = std::basic_string<CharType>>
5911
class output_adapter
5912
{
5913
  public:
5914
    output_adapter(std::vector<CharType>& vec)
5915
        : oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}
5916
5917
    output_adapter(std::basic_ostream<CharType>& s)
39
5918
        : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
5919
5920
    output_adapter(StringType& s)
15
5921
        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
5922
5923
    operator output_adapter_t<CharType>()
54
5924
    {
54
5925
        return oa;
54
5926
    }
5927
5928
  private:
5929
    output_adapter_t<CharType> oa = nullptr;
5930
};
5931
}
5932
}
5933
5934
// #include <nlohmann/detail/input/binary_reader.hpp>
5935
5936
5937
#include <algorithm> // generate_n
5938
#include <array> // array
5939
#include <cassert> // assert
5940
#include <cmath> // ldexp
5941
#include <cstddef> // size_t
5942
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
5943
#include <cstdio> // snprintf
5944
#include <cstring> // memcpy
5945
#include <iterator> // back_inserter
5946
#include <limits> // numeric_limits
5947
#include <string> // char_traits, string
5948
#include <utility> // make_pair, move
5949
5950
// #include <nlohmann/detail/input/input_adapters.hpp>
5951
5952
// #include <nlohmann/detail/input/json_sax.hpp>
5953
5954
// #include <nlohmann/detail/exceptions.hpp>
5955
5956
// #include <nlohmann/detail/macro_scope.hpp>
5957
5958
// #include <nlohmann/detail/meta/is_sax.hpp>
5959
5960
// #include <nlohmann/detail/value_t.hpp>
5961
5962
5963
namespace nlohmann
5964
{
5965
namespace detail
5966
{
5967
///////////////////
5968
// binary reader //
5969
///////////////////
5970
5971
/*!
5972
@brief deserialization of CBOR, MessagePack, and UBJSON values
5973
*/
5974
template<typename BasicJsonType, typename SAX = json_sax_dom_parser<BasicJsonType>>
5975
class binary_reader
5976
{
5977
    using number_integer_t = typename BasicJsonType::number_integer_t;
5978
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
5979
    using number_float_t = typename BasicJsonType::number_float_t;
5980
    using string_t = typename BasicJsonType::string_t;
5981
    using json_sax_t = SAX;
5982
5983
  public:
5984
    /*!
5985
    @brief create a binary reader
5986
5987
    @param[in] adapter  input adapter to read from
5988
    */
5989
    explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter))
5990
    {
5991
        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
5992
        assert(ia);
5993
    }
5994
5995
    /*!
5996
    @param[in] format  the binary format to parse
5997
    @param[in] sax_    a SAX event processor
5998
    @param[in] strict  whether to expect the input to be consumed completed
5999
6000
    @return
6001
    */
6002
    bool sax_parse(const input_format_t format,
6003
                   json_sax_t* sax_,
6004
                   const bool strict = true)
6005
    {
6006
        sax = sax_;
6007
        bool result = false;
6008
6009
        switch (format)
6010
        {
6011
            case input_format_t::cbor:
6012
                result = parse_cbor_internal();
6013
                break;
6014
6015
            case input_format_t::msgpack:
6016
                result = parse_msgpack_internal();
6017
                break;
6018
6019
            case input_format_t::ubjson:
6020
                result = parse_ubjson_internal();
6021
                break;
6022
6023
            // LCOV_EXCL_START
6024
            default:
6025
                assert(false);
6026
                // LCOV_EXCL_STOP
6027
        }
6028
6029
        // strict mode: next byte must be EOF
6030
        if (result and strict)
6031
        {
6032
            if (format == input_format_t::ubjson)
6033
            {
6034
                get_ignore_noop();
6035
            }
6036
            else
6037
            {
6038
                get();
6039
            }
6040
6041
            if (JSON_UNLIKELY(current != std::char_traits<char>::eof()))
6042
            {
6043
                return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, "expected end of input"));
6044
            }
6045
        }
6046
6047
        return result;
6048
    }
6049
6050
    /*!
6051
    @brief determine system byte order
6052
6053
    @return true if and only if system's byte order is little endian
6054
6055
    @note from http://stackoverflow.com/a/1001328/266378
6056
    */
6057
    static constexpr bool little_endianess(int num = 1) noexcept
6058
    {
6059
        return (*reinterpret_cast<char*>(&num) == 1);
6060
    }
6061
6062
  private:
6063
    /*!
6064
    @param[in] get_char  whether a new character should be retrieved from the
6065
                         input (true, default) or whether the last read
6066
                         character should be considered instead
6067
6068
    @return whether a valid CBOR value was passed to the SAX parser
6069
    */
6070
    bool parse_cbor_internal(const bool get_char = true)
6071
    {
6072
        switch (get_char ? get() : current)
6073
        {
6074
            // EOF
6075
            case std::char_traits<char>::eof():
6076
                return unexpect_eof();
6077
6078
            // Integer 0x00..0x17 (0..23)
6079
            case 0x00:
6080
            case 0x01:
6081
            case 0x02:
6082
            case 0x03:
6083
            case 0x04:
6084
            case 0x05:
6085
            case 0x06:
6086
            case 0x07:
6087
            case 0x08:
6088
            case 0x09:
6089
            case 0x0A:
6090
            case 0x0B:
6091
            case 0x0C:
6092
            case 0x0D:
6093
            case 0x0E:
6094
            case 0x0F:
6095
            case 0x10:
6096
            case 0x11:
6097
            case 0x12:
6098
            case 0x13:
6099
            case 0x14:
6100
            case 0x15:
6101
            case 0x16:
6102
            case 0x17:
6103
                return sax->number_unsigned(static_cast<number_unsigned_t>(current));
6104
6105
            case 0x18: // Unsigned integer (one-byte uint8_t follows)
6106
            {
6107
                uint8_t number;
6108
                return get_number(number) and sax->number_unsigned(number);
6109
            }
6110
6111
            case 0x19: // Unsigned integer (two-byte uint16_t follows)
6112
            {
6113
                uint16_t number;
6114
                return get_number(number) and sax->number_unsigned(number);
6115
            }
6116
6117
            case 0x1A: // Unsigned integer (four-byte uint32_t follows)
6118
            {
6119
                uint32_t number;
6120
                return get_number(number) and sax->number_unsigned(number);
6121
            }
6122
6123
            case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
6124
            {
6125
                uint64_t number;
6126
                return get_number(number) and sax->number_unsigned(number);
6127
            }
6128
6129
            // Negative integer -1-0x00..-1-0x17 (-1..-24)
6130
            case 0x20:
6131
            case 0x21:
6132
            case 0x22:
6133
            case 0x23:
6134
            case 0x24:
6135
            case 0x25:
6136
            case 0x26:
6137
            case 0x27:
6138
            case 0x28:
6139
            case 0x29:
6140
            case 0x2A:
6141
            case 0x2B:
6142
            case 0x2C:
6143
            case 0x2D:
6144
            case 0x2E:
6145
            case 0x2F:
6146
            case 0x30:
6147
            case 0x31:
6148
            case 0x32:
6149
            case 0x33:
6150
            case 0x34:
6151
            case 0x35:
6152
            case 0x36:
6153
            case 0x37:
6154
                return sax->number_integer(static_cast<int8_t>(0x20 - 1 - current));
6155
6156
            case 0x38: // Negative integer (one-byte uint8_t follows)
6157
            {
6158
                uint8_t number;
6159
                return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
6160
            }
6161
6162
            case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
6163
            {
6164
                uint16_t number;
6165
                return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
6166
            }
6167
6168
            case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
6169
            {
6170
                uint32_t number;
6171
                return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
6172
            }
6173
6174
            case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
6175
            {
6176
                uint64_t number;
6177
                return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1)
6178
                        - static_cast<number_integer_t>(number));
6179
            }
6180
6181
            // UTF-8 string (0x00..0x17 bytes follow)
6182
            case 0x60:
6183
            case 0x61:
6184
            case 0x62:
6185
            case 0x63:
6186
            case 0x64:
6187
            case 0x65:
6188
            case 0x66:
6189
            case 0x67:
6190
            case 0x68:
6191
            case 0x69:
6192
            case 0x6A:
6193
            case 0x6B:
6194
            case 0x6C:
6195
            case 0x6D:
6196
            case 0x6E:
6197
            case 0x6F:
6198
            case 0x70:
6199
            case 0x71:
6200
            case 0x72:
6201
            case 0x73:
6202
            case 0x74:
6203
            case 0x75:
6204
            case 0x76:
6205
            case 0x77:
6206
            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
6207
            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
6208
            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
6209
            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
6210
            case 0x7F: // UTF-8 string (indefinite length)
6211
            {
6212
                string_t s;
6213
                return get_cbor_string(s) and sax->string(s);
6214
            }
6215
6216
            // array (0x00..0x17 data items follow)
6217
            case 0x80:
6218
            case 0x81:
6219
            case 0x82:
6220
            case 0x83:
6221
            case 0x84:
6222
            case 0x85:
6223
            case 0x86:
6224
            case 0x87:
6225
            case 0x88:
6226
            case 0x89:
6227
            case 0x8A:
6228
            case 0x8B:
6229
            case 0x8C:
6230
            case 0x8D:
6231
            case 0x8E:
6232
            case 0x8F:
6233
            case 0x90:
6234
            case 0x91:
6235
            case 0x92:
6236
            case 0x93:
6237
            case 0x94:
6238
            case 0x95:
6239
            case 0x96:
6240
            case 0x97:
6241
                return get_cbor_array(static_cast<std::size_t>(current & 0x1F));
6242
6243
            case 0x98: // array (one-byte uint8_t for n follows)
6244
            {
6245
                uint8_t len;
6246
                return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
6247
            }
6248
6249
            case 0x99: // array (two-byte uint16_t for n follow)
6250
            {
6251
                uint16_t len;
6252
                return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
6253
            }
6254
6255
            case 0x9A: // array (four-byte uint32_t for n follow)
6256
            {
6257
                uint32_t len;
6258
                return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
6259
            }
6260
6261
            case 0x9B: // array (eight-byte uint64_t for n follow)
6262
            {
6263
                uint64_t len;
6264
                return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
6265
            }
6266
6267
            case 0x9F: // array (indefinite length)
6268
                return get_cbor_array(std::size_t(-1));
6269
6270
            // map (0x00..0x17 pairs of data items follow)
6271
            case 0xA0:
6272
            case 0xA1:
6273
            case 0xA2:
6274
            case 0xA3:
6275
            case 0xA4:
6276
            case 0xA5:
6277
            case 0xA6:
6278
            case 0xA7:
6279
            case 0xA8:
6280
            case 0xA9:
6281
            case 0xAA:
6282
            case 0xAB:
6283
            case 0xAC:
6284
            case 0xAD:
6285
            case 0xAE:
6286
            case 0xAF:
6287
            case 0xB0:
6288
            case 0xB1:
6289
            case 0xB2:
6290
            case 0xB3:
6291
            case 0xB4:
6292
            case 0xB5:
6293
            case 0xB6:
6294
            case 0xB7:
6295
                return get_cbor_object(static_cast<std::size_t>(current & 0x1F));
6296
6297
            case 0xB8: // map (one-byte uint8_t for n follows)
6298
            {
6299
                uint8_t len;
6300
                return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
6301
            }
6302
6303
            case 0xB9: // map (two-byte uint16_t for n follow)
6304
            {
6305
                uint16_t len;
6306
                return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
6307
            }
6308
6309
            case 0xBA: // map (four-byte uint32_t for n follow)
6310
            {
6311
                uint32_t len;
6312
                return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
6313
            }
6314
6315
            case 0xBB: // map (eight-byte uint64_t for n follow)
6316
            {
6317
                uint64_t len;
6318
                return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
6319
            }
6320
6321
            case 0xBF: // map (indefinite length)
6322
                return get_cbor_object(std::size_t(-1));
6323
6324
            case 0xF4: // false
6325
                return sax->boolean(false);
6326
6327
            case 0xF5: // true
6328
                return sax->boolean(true);
6329
6330
            case 0xF6: // null
6331
                return sax->null();
6332
6333
            case 0xF9: // Half-Precision Float (two-byte IEEE 754)
6334
            {
6335
                const int byte1 = get();
6336
                if (JSON_UNLIKELY(not unexpect_eof()))
6337
                {
6338
                    return false;
6339
                }
6340
                const int byte2 = get();
6341
                if (JSON_UNLIKELY(not unexpect_eof()))
6342
                {
6343
                    return false;
6344
                }
6345
6346
                // code from RFC 7049, Appendix D, Figure 3:
6347
                // As half-precision floating-point numbers were only added
6348
                // to IEEE 754 in 2008, today's programming platforms often
6349
                // still only have limited support for them. It is very
6350
                // easy to include at least decoding support for them even
6351
                // without such support. An example of a small decoder for
6352
                // half-precision floating-point numbers in the C language
6353
                // is shown in Fig. 3.
6354
                const int half = (byte1 << 8) + byte2;
6355
                const double val = [&half]
6356
                {
6357
                    const int exp = (half >> 10) & 0x1F;
6358
                    const int mant = half & 0x3FF;
6359
                    assert(0 <= exp and exp <= 32);
6360
                    assert(0 <= mant and mant <= 1024);
6361
                    switch (exp)
6362
                    {
6363
                        case 0:
6364
                            return std::ldexp(mant, -24);
6365
                        case 31:
6366
                            return (mant == 0)
6367
                            ? std::numeric_limits<double>::infinity()
6368
                            : std::numeric_limits<double>::quiet_NaN();
6369
                        default:
6370
                            return std::ldexp(mant + 1024, exp - 25);
6371
                    }
6372
                }();
6373
                return sax->number_float((half & 0x8000) != 0
6374
                                         ? static_cast<number_float_t>(-val)
6375
                                         : static_cast<number_float_t>(val), "");
6376
            }
6377
6378
            case 0xFA: // Single-Precision Float (four-byte IEEE 754)
6379
            {
6380
                float number;
6381
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
6382
            }
6383
6384
            case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
6385
            {
6386
                double number;
6387
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
6388
            }
6389
6390
            default: // anything else (0xFF is handled inside the other types)
6391
            {
6392
                auto last_token = get_token_string();
6393
                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + last_token));
6394
            }
6395
        }
6396
    }
6397
6398
    /*!
6399
    @return whether a valid MessagePack value was passed to the SAX parser
6400
    */
6401
    bool parse_msgpack_internal()
6402
    {
6403
        switch (get())
6404
        {
6405
            // EOF
6406
            case std::char_traits<char>::eof():
6407
                return unexpect_eof();
6408
6409
            // positive fixint
6410
            case 0x00:
6411
            case 0x01:
6412
            case 0x02:
6413
            case 0x03:
6414
            case 0x04:
6415
            case 0x05:
6416
            case 0x06:
6417
            case 0x07:
6418
            case 0x08:
6419
            case 0x09:
6420
            case 0x0A:
6421
            case 0x0B:
6422
            case 0x0C:
6423
            case 0x0D:
6424
            case 0x0E:
6425
            case 0x0F:
6426
            case 0x10:
6427
            case 0x11:
6428
            case 0x12:
6429
            case 0x13:
6430
            case 0x14:
6431
            case 0x15:
6432
            case 0x16:
6433
            case 0x17:
6434
            case 0x18:
6435
            case 0x19:
6436
            case 0x1A:
6437
            case 0x1B:
6438
            case 0x1C:
6439
            case 0x1D:
6440
            case 0x1E:
6441
            case 0x1F:
6442
            case 0x20:
6443
            case 0x21:
6444
            case 0x22:
6445
            case 0x23:
6446
            case 0x24:
6447
            case 0x25:
6448
            case 0x26:
6449
            case 0x27:
6450
            case 0x28:
6451
            case 0x29:
6452
            case 0x2A:
6453
            case 0x2B:
6454
            case 0x2C:
6455
            case 0x2D:
6456
            case 0x2E:
6457
            case 0x2F:
6458
            case 0x30:
6459
            case 0x31:
6460
            case 0x32:
6461
            case 0x33:
6462
            case 0x34:
6463
            case 0x35:
6464
            case 0x36:
6465
            case 0x37:
6466
            case 0x38:
6467
            case 0x39:
6468
            case 0x3A:
6469
            case 0x3B:
6470
            case 0x3C:
6471
            case 0x3D:
6472
            case 0x3E:
6473
            case 0x3F:
6474
            case 0x40:
6475
            case 0x41:
6476
            case 0x42:
6477
            case 0x43:
6478
            case 0x44:
6479
            case 0x45:
6480
            case 0x46:
6481
            case 0x47:
6482
            case 0x48:
6483
            case 0x49:
6484
            case 0x4A:
6485
            case 0x4B:
6486
            case 0x4C:
6487
            case 0x4D:
6488
            case 0x4E:
6489
            case 0x4F:
6490
            case 0x50:
6491
            case 0x51:
6492
            case 0x52:
6493
            case 0x53:
6494
            case 0x54:
6495
            case 0x55:
6496
            case 0x56:
6497
            case 0x57:
6498
            case 0x58:
6499
            case 0x59:
6500
            case 0x5A:
6501
            case 0x5B:
6502
            case 0x5C:
6503
            case 0x5D:
6504
            case 0x5E:
6505
            case 0x5F:
6506
            case 0x60:
6507
            case 0x61:
6508
            case 0x62:
6509
            case 0x63:
6510
            case 0x64:
6511
            case 0x65:
6512
            case 0x66:
6513
            case 0x67:
6514
            case 0x68:
6515
            case 0x69:
6516
            case 0x6A:
6517
            case 0x6B:
6518
            case 0x6C:
6519
            case 0x6D:
6520
            case 0x6E:
6521
            case 0x6F:
6522
            case 0x70:
6523
            case 0x71:
6524
            case 0x72:
6525
            case 0x73:
6526
            case 0x74:
6527
            case 0x75:
6528
            case 0x76:
6529
            case 0x77:
6530
            case 0x78:
6531
            case 0x79:
6532
            case 0x7A:
6533
            case 0x7B:
6534
            case 0x7C:
6535
            case 0x7D:
6536
            case 0x7E:
6537
            case 0x7F:
6538
                return sax->number_unsigned(static_cast<number_unsigned_t>(current));
6539
6540
            // fixmap
6541
            case 0x80:
6542
            case 0x81:
6543
            case 0x82:
6544
            case 0x83:
6545
            case 0x84:
6546
            case 0x85:
6547
            case 0x86:
6548
            case 0x87:
6549
            case 0x88:
6550
            case 0x89:
6551
            case 0x8A:
6552
            case 0x8B:
6553
            case 0x8C:
6554
            case 0x8D:
6555
            case 0x8E:
6556
            case 0x8F:
6557
                return get_msgpack_object(static_cast<std::size_t>(current & 0x0F));
6558
6559
            // fixarray
6560
            case 0x90:
6561
            case 0x91:
6562
            case 0x92:
6563
            case 0x93:
6564
            case 0x94:
6565
            case 0x95:
6566
            case 0x96:
6567
            case 0x97:
6568
            case 0x98:
6569
            case 0x99:
6570
            case 0x9A:
6571
            case 0x9B:
6572
            case 0x9C:
6573
            case 0x9D:
6574
            case 0x9E:
6575
            case 0x9F:
6576
                return get_msgpack_array(static_cast<std::size_t>(current & 0x0F));
6577
6578
            // fixstr
6579
            case 0xA0:
6580
            case 0xA1:
6581
            case 0xA2:
6582
            case 0xA3:
6583
            case 0xA4:
6584
            case 0xA5:
6585
            case 0xA6:
6586
            case 0xA7:
6587
            case 0xA8:
6588
            case 0xA9:
6589
            case 0xAA:
6590
            case 0xAB:
6591
            case 0xAC:
6592
            case 0xAD:
6593
            case 0xAE:
6594
            case 0xAF:
6595
            case 0xB0:
6596
            case 0xB1:
6597
            case 0xB2:
6598
            case 0xB3:
6599
            case 0xB4:
6600
            case 0xB5:
6601
            case 0xB6:
6602
            case 0xB7:
6603
            case 0xB8:
6604
            case 0xB9:
6605
            case 0xBA:
6606
            case 0xBB:
6607
            case 0xBC:
6608
            case 0xBD:
6609
            case 0xBE:
6610
            case 0xBF:
6611
            {
6612
                string_t s;
6613
                return get_msgpack_string(s) and sax->string(s);
6614
            }
6615
6616
            case 0xC0: // nil
6617
                return sax->null();
6618
6619
            case 0xC2: // false
6620
                return sax->boolean(false);
6621
6622
            case 0xC3: // true
6623
                return sax->boolean(true);
6624
6625
            case 0xCA: // float 32
6626
            {
6627
                float number;
6628
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
6629
            }
6630
6631
            case 0xCB: // float 64
6632
            {
6633
                double number;
6634
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
6635
            }
6636
6637
            case 0xCC: // uint 8
6638
            {
6639
                uint8_t number;
6640
                return get_number(number) and sax->number_unsigned(number);
6641
            }
6642
6643
            case 0xCD: // uint 16
6644
            {
6645
                uint16_t number;
6646
                return get_number(number) and sax->number_unsigned(number);
6647
            }
6648
6649
            case 0xCE: // uint 32
6650
            {
6651
                uint32_t number;
6652
                return get_number(number) and sax->number_unsigned(number);
6653
            }
6654
6655
            case 0xCF: // uint 64
6656
            {
6657
                uint64_t number;
6658
                return get_number(number) and sax->number_unsigned(number);
6659
            }
6660
6661
            case 0xD0: // int 8
6662
            {
6663
                int8_t number;
6664
                return get_number(number) and sax->number_integer(number);
6665
            }
6666
6667
            case 0xD1: // int 16
6668
            {
6669
                int16_t number;
6670
                return get_number(number) and sax->number_integer(number);
6671
            }
6672
6673
            case 0xD2: // int 32
6674
            {
6675
                int32_t number;
6676
                return get_number(number) and sax->number_integer(number);
6677
            }
6678
6679
            case 0xD3: // int 64
6680
            {
6681
                int64_t number;
6682
                return get_number(number) and sax->number_integer(number);
6683
            }
6684
6685
            case 0xD9: // str 8
6686
            case 0xDA: // str 16
6687
            case 0xDB: // str 32
6688
            {
6689
                string_t s;
6690
                return get_msgpack_string(s) and sax->string(s);
6691
            }
6692
6693
            case 0xDC: // array 16
6694
            {
6695
                uint16_t len;
6696
                return get_number(len) and get_msgpack_array(static_cast<std::size_t>(len));
6697
            }
6698
6699
            case 0xDD: // array 32
6700
            {
6701
                uint32_t len;
6702
                return get_number(len) and get_msgpack_array(static_cast<std::size_t>(len));
6703
            }
6704
6705
            case 0xDE: // map 16
6706
            {
6707
                uint16_t len;
6708
                return get_number(len) and get_msgpack_object(static_cast<std::size_t>(len));
6709
            }
6710
6711
            case 0xDF: // map 32
6712
            {
6713
                uint32_t len;
6714
                return get_number(len) and get_msgpack_object(static_cast<std::size_t>(len));
6715
            }
6716
6717
            // negative fixint
6718
            case 0xE0:
6719
            case 0xE1:
6720
            case 0xE2:
6721
            case 0xE3:
6722
            case 0xE4:
6723
            case 0xE5:
6724
            case 0xE6:
6725
            case 0xE7:
6726
            case 0xE8:
6727
            case 0xE9:
6728
            case 0xEA:
6729
            case 0xEB:
6730
            case 0xEC:
6731
            case 0xED:
6732
            case 0xEE:
6733
            case 0xEF:
6734
            case 0xF0:
6735
            case 0xF1:
6736
            case 0xF2:
6737
            case 0xF3:
6738
            case 0xF4:
6739
            case 0xF5:
6740
            case 0xF6:
6741
            case 0xF7:
6742
            case 0xF8:
6743
            case 0xF9:
6744
            case 0xFA:
6745
            case 0xFB:
6746
            case 0xFC:
6747
            case 0xFD:
6748
            case 0xFE:
6749
            case 0xFF:
6750
                return sax->number_integer(static_cast<int8_t>(current));
6751
6752
            default: // anything else
6753
            {
6754
                auto last_token = get_token_string();
6755
                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading MessagePack; last byte: 0x" + last_token));
6756
            }
6757
        }
6758
    }
6759
6760
    /*!
6761
    @param[in] get_char  whether a new character should be retrieved from the
6762
                         input (true, default) or whether the last read
6763
                         character should be considered instead
6764
6765
    @return whether a valid UBJSON value was passed to the SAX parser
6766
    */
6767
    bool parse_ubjson_internal(const bool get_char = true)
6768
    {
6769
        return get_ubjson_value(get_char ? get_ignore_noop() : current);
6770
    }
6771
6772
    /*!
6773
    @brief get next character from the input
6774
6775
    This function provides the interface to the used input adapter. It does
6776
    not throw in case the input reached EOF, but returns a -'ve valued
6777
    `std::char_traits<char>::eof()` in that case.
6778
6779
    @return character read from the input
6780
    */
6781
    int get()
6782
    {
6783
        ++chars_read;
6784
        return (current = ia->get_character());
6785
    }
6786
6787
    /*!
6788
    @return character read from the input after ignoring all 'N' entries
6789
    */
6790
    int get_ignore_noop()
6791
    {
6792
        do
6793
        {
6794
            get();
6795
        }
6796
        while (current == 'N');
6797
6798
        return current;
6799
    }
6800
6801
    /*
6802
    @brief read a number from the input
6803
6804
    @tparam NumberType the type of the number
6805
    @param[out] result  number of type @a NumberType
6806
6807
    @return whether conversion completed
6808
6809
    @note This function needs to respect the system's endianess, because
6810
          bytes in CBOR, MessagePack, and UBJSON are stored in network order
6811
          (big endian) and therefore need reordering on little endian systems.
6812
    */
6813
    template<typename NumberType>
6814
    bool get_number(NumberType& result)
6815
    {
6816
        // step 1: read input into array with system's byte order
6817
        std::array<uint8_t, sizeof(NumberType)> vec;
6818
        for (std::size_t i = 0; i < sizeof(NumberType); ++i)
6819
        {
6820
            get();
6821
            if (JSON_UNLIKELY(not unexpect_eof()))
6822
            {
6823
                return false;
6824
            }
6825
6826
            // reverse byte order prior to conversion if necessary
6827
            if (is_little_endian)
6828
            {
6829
                vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current);
6830
            }
6831
            else
6832
            {
6833
                vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE
6834
            }
6835
        }
6836
6837
        // step 2: convert array into number of type T and return
6838
        std::memcpy(&result, vec.data(), sizeof(NumberType));
6839
        return true;
6840
    }
6841
6842
    /*!
6843
    @brief create a string by reading characters from the input
6844
6845
    @tparam NumberType the type of the number
6846
    @param[in] len number of characters to read
6847
    @param[out] string created by reading @a len bytes
6848
6849
    @return whether string creation completed
6850
6851
    @note We can not reserve @a len bytes for the result, because @a len
6852
          may be too large. Usually, @ref unexpect_eof() detects the end of
6853
          the input before we run out of string memory.
6854
    */
6855
    template<typename NumberType>
6856
    bool get_string(const NumberType len, string_t& result)
6857
    {
6858
        bool success = true;
6859
        std::generate_n(std::back_inserter(result), len, [this, &success]()
6860
        {
6861
            get();
6862
            if (JSON_UNLIKELY(not unexpect_eof()))
6863
            {
6864
                success = false;
6865
            }
6866
            return static_cast<char>(current);
6867
        });
6868
        return success;
6869
    }
6870
6871
    /*!
6872
    @brief reads a CBOR string
6873
6874
    This function first reads starting bytes to determine the expected
6875
    string length and then copies this number of bytes into a string.
6876
    Additionally, CBOR's strings with indefinite lengths are supported.
6877
6878
    @param[out] result  created string
6879
6880
    @return whether string creation completed
6881
    */
6882
    bool get_cbor_string(string_t& result)
6883
    {
6884
        if (JSON_UNLIKELY(not unexpect_eof()))
6885
        {
6886
            return false;
6887
        }
6888
6889
        switch (current)
6890
        {
6891
            // UTF-8 string (0x00..0x17 bytes follow)
6892
            case 0x60:
6893
            case 0x61:
6894
            case 0x62:
6895
            case 0x63:
6896
            case 0x64:
6897
            case 0x65:
6898
            case 0x66:
6899
            case 0x67:
6900
            case 0x68:
6901
            case 0x69:
6902
            case 0x6A:
6903
            case 0x6B:
6904
            case 0x6C:
6905
            case 0x6D:
6906
            case 0x6E:
6907
            case 0x6F:
6908
            case 0x70:
6909
            case 0x71:
6910
            case 0x72:
6911
            case 0x73:
6912
            case 0x74:
6913
            case 0x75:
6914
            case 0x76:
6915
            case 0x77:
6916
            {
6917
                return get_string(current & 0x1F, result);
6918
            }
6919
6920
            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
6921
            {
6922
                uint8_t len;
6923
                return get_number(len) and get_string(len, result);
6924
            }
6925
6926
            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
6927
            {
6928
                uint16_t len;
6929
                return get_number(len) and get_string(len, result);
6930
            }
6931
6932
            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
6933
            {
6934
                uint32_t len;
6935
                return get_number(len) and get_string(len, result);
6936
            }
6937
6938
            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
6939
            {
6940
                uint64_t len;
6941
                return get_number(len) and get_string(len, result);
6942
            }
6943
6944
            case 0x7F: // UTF-8 string (indefinite length)
6945
            {
6946
                while (get() != 0xFF)
6947
                {
6948
                    string_t chunk;
6949
                    if (not get_cbor_string(chunk))
6950
                    {
6951
                        return false;
6952
                    }
6953
                    result.append(chunk);
6954
                }
6955
                return true;
6956
            }
6957
6958
            default:
6959
            {
6960
                auto last_token = get_token_string();
6961
                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + last_token));
6962
            }
6963
        }
6964
    }
6965
6966
    /*!
6967
    @param[in] len  the length of the array or std::size_t(-1) for an
6968
                    array of indefinite size
6969
    @return whether array creation completed
6970
    */
6971
    bool get_cbor_array(const std::size_t len)
6972
    {
6973
        if (JSON_UNLIKELY(not sax->start_array(len)))
6974
        {
6975
            return false;
6976
        }
6977
6978
        if (len != std::size_t(-1))
6979
            for (std::size_t i = 0; i < len; ++i)
6980
            {
6981
                if (JSON_UNLIKELY(not parse_cbor_internal()))
6982
                {
6983
                    return false;
6984
                }
6985
            }
6986
        else
6987
        {
6988
            while (get() != 0xFF)
6989
            {
6990
                if (JSON_UNLIKELY(not parse_cbor_internal(false)))
6991
                {
6992
                    return false;
6993
                }
6994
            }
6995
        }
6996
6997
        return sax->end_array();
6998
    }
6999
7000
    /*!
7001
    @param[in] len  the length of the object or std::size_t(-1) for an
7002
                    object of indefinite size
7003
    @return whether object creation completed
7004
    */
7005
    bool get_cbor_object(const std::size_t len)
7006
    {
7007
        if (not JSON_UNLIKELY(sax->start_object(len)))
7008
        {
7009
            return false;
7010
        }
7011
7012
        string_t key;
7013
        if (len != std::size_t(-1))
7014
        {
7015
            for (std::size_t i = 0; i < len; ++i)
7016
            {
7017
                get();
7018
                if (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))
7019
                {
7020
                    return false;
7021
                }
7022
7023
                if (JSON_UNLIKELY(not parse_cbor_internal()))
7024
                {
7025
                    return false;
7026
                }
7027
                key.clear();
7028
            }
7029
        }
7030
        else
7031
        {
7032
            while (get() != 0xFF)
7033
            {
7034
                if (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))
7035
                {
7036
                    return false;
7037
                }
7038
7039
                if (JSON_UNLIKELY(not parse_cbor_internal()))
7040
                {
7041
                    return false;
7042
                }
7043
                key.clear();
7044
            }
7045
        }
7046
7047
        return sax->end_object();
7048
    }
7049
7050
    /*!
7051
    @brief reads a MessagePack string
7052
7053
    This function first reads starting bytes to determine the expected
7054
    string length and then copies this number of bytes into a string.
7055
7056
    @param[out] result  created string
7057
7058
    @return whether string creation completed
7059
    */
7060
    bool get_msgpack_string(string_t& result)
7061
    {
7062
        if (JSON_UNLIKELY(not unexpect_eof()))
7063
        {
7064
            return false;
7065
        }
7066
7067
        switch (current)
7068
        {
7069
            // fixstr
7070
            case 0xA0:
7071
            case 0xA1:
7072
            case 0xA2:
7073
            case 0xA3:
7074
            case 0xA4:
7075
            case 0xA5:
7076
            case 0xA6:
7077
            case 0xA7:
7078
            case 0xA8:
7079
            case 0xA9:
7080
            case 0xAA:
7081
            case 0xAB:
7082
            case 0xAC:
7083
            case 0xAD:
7084
            case 0xAE:
7085
            case 0xAF:
7086
            case 0xB0:
7087
            case 0xB1:
7088
            case 0xB2:
7089
            case 0xB3:
7090
            case 0xB4:
7091
            case 0xB5:
7092
            case 0xB6:
7093
            case 0xB7:
7094
            case 0xB8:
7095
            case 0xB9:
7096
            case 0xBA:
7097
            case 0xBB:
7098
            case 0xBC:
7099
            case 0xBD:
7100
            case 0xBE:
7101
            case 0xBF:
7102
            {
7103
                return get_string(current & 0x1F, result);
7104
            }
7105
7106
            case 0xD9: // str 8
7107
            {
7108
                uint8_t len;
7109
                return get_number(len) and get_string(len, result);
7110
            }
7111
7112
            case 0xDA: // str 16
7113
            {
7114
                uint16_t len;
7115
                return get_number(len) and get_string(len, result);
7116
            }
7117
7118
            case 0xDB: // str 32
7119
            {
7120
                uint32_t len;
7121
                return get_number(len) and get_string(len, result);
7122
            }
7123
7124
            default:
7125
            {
7126
                auto last_token = get_token_string();
7127
                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a MessagePack string; last byte: 0x" + last_token));
7128
            }
7129
        }
7130
    }
7131
7132
    /*!
7133
    @param[in] len  the length of the array
7134
    @return whether array creation completed
7135
    */
7136
    bool get_msgpack_array(const std::size_t len)
7137
    {
7138
        if (JSON_UNLIKELY(not sax->start_array(len)))
7139
        {
7140
            return false;
7141
        }
7142
7143
        for (std::size_t i = 0; i < len; ++i)
7144
        {
7145
            if (JSON_UNLIKELY(not parse_msgpack_internal()))
7146
            {
7147
                return false;
7148
            }
7149
        }
7150
7151
        return sax->end_array();
7152
    }
7153
7154
    /*!
7155
    @param[in] len  the length of the object
7156
    @return whether object creation completed
7157
    */
7158
    bool get_msgpack_object(const std::size_t len)
7159
    {
7160
        if (JSON_UNLIKELY(not sax->start_object(len)))
7161
        {
7162
            return false;
7163
        }
7164
7165
        string_t key;
7166
        for (std::size_t i = 0; i < len; ++i)
7167
        {
7168
            get();
7169
            if (JSON_UNLIKELY(not get_msgpack_string(key) or not sax->key(key)))
7170
            {
7171
                return false;
7172
            }
7173
7174
            if (JSON_UNLIKELY(not parse_msgpack_internal()))
7175
            {
7176
                return false;
7177
            }
7178
            key.clear();
7179
        }
7180
7181
        return sax->end_object();
7182
    }
7183
7184
    /*!
7185
    @brief reads a UBJSON string
7186
7187
    This function is either called after reading the 'S' byte explicitly
7188
    indicating a string, or in case of an object key where the 'S' byte can be
7189
    left out.
7190
7191
    @param[out] result   created string
7192
    @param[in] get_char  whether a new character should be retrieved from the
7193
                         input (true, default) or whether the last read
7194
                         character should be considered instead
7195
7196
    @return whether string creation completed
7197
    */
7198
    bool get_ubjson_string(string_t& result, const bool get_char = true)
7199
    {
7200
        if (get_char)
7201
        {
7202
            get();  // TODO: may we ignore N here?
7203
        }
7204
7205
        if (JSON_UNLIKELY(not unexpect_eof()))
7206
        {
7207
            return false;
7208
        }
7209
7210
        switch (current)
7211
        {
7212
            case 'U':
7213
            {
7214
                uint8_t len;
7215
                return get_number(len) and get_string(len, result);
7216
            }
7217
7218
            case 'i':
7219
            {
7220
                int8_t len;
7221
                return get_number(len) and get_string(len, result);
7222
            }
7223
7224
            case 'I':
7225
            {
7226
                int16_t len;
7227
                return get_number(len) and get_string(len, result);
7228
            }
7229
7230
            case 'l':
7231
            {
7232
                int32_t len;
7233
                return get_number(len) and get_string(len, result);
7234
            }
7235
7236
            case 'L':
7237
            {
7238
                int64_t len;
7239
                return get_number(len) and get_string(len, result);
7240
            }
7241
7242
            default:
7243
                auto last_token = get_token_string();
7244
                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a UBJSON string; last byte: 0x" + last_token));
7245
        }
7246
    }
7247
7248
    /*!
7249
    @param[out] result  determined size
7250
    @return whether size determination completed
7251
    */
7252
    bool get_ubjson_size_value(std::size_t& result)
7253
    {
7254
        switch (get_ignore_noop())
7255
        {
7256
            case 'U':
7257
            {
7258
                uint8_t number;
7259
                if (JSON_UNLIKELY(not get_number(number)))
7260
                {
7261
                    return false;
7262
                }
7263
                result = static_cast<std::size_t>(number);
7264
                return true;
7265
            }
7266
7267
            case 'i':
7268
            {
7269
                int8_t number;
7270
                if (JSON_UNLIKELY(not get_number(number)))
7271
                {
7272
                    return false;
7273
                }
7274
                result = static_cast<std::size_t>(number);
7275
                return true;
7276
            }
7277
7278
            case 'I':
7279
            {
7280
                int16_t number;
7281
                if (JSON_UNLIKELY(not get_number(number)))
7282
                {
7283
                    return false;
7284
                }
7285
                result = static_cast<std::size_t>(number);
7286
                return true;
7287
            }
7288
7289
            case 'l':
7290
            {
7291
                int32_t number;
7292
                if (JSON_UNLIKELY(not get_number(number)))
7293
                {
7294
                    return false;
7295
                }
7296
                result = static_cast<std::size_t>(number);
7297
                return true;
7298
            }
7299
7300
            case 'L':
7301
            {
7302
                int64_t number;
7303
                if (JSON_UNLIKELY(not get_number(number)))
7304
                {
7305
                    return false;
7306
                }
7307
                result = static_cast<std::size_t>(number);
7308
                return true;
7309
            }
7310
7311
            default:
7312
            {
7313
                auto last_token = get_token_string();
7314
                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "byte after '#' must denote a number type; last byte: 0x" + last_token));
7315
            }
7316
        }
7317
    }
7318
7319
    /*!
7320
    @brief determine the type and size for a container
7321
7322
    In the optimized UBJSON format, a type and a size can be provided to allow
7323
    for a more compact representation.
7324
7325
    @param[out] result  pair of the size and the type
7326
7327
    @return whether pair creation completed
7328
    */
7329
    bool get_ubjson_size_type(std::pair<std::size_t, int>& result)
7330
    {
7331
        result.first = string_t::npos; // size
7332
        result.second = 0; // type
7333
7334
        get_ignore_noop();
7335
7336
        if (current == '$')
7337
        {
7338
            result.second = get();  // must not ignore 'N', because 'N' maybe the type
7339
            if (JSON_UNLIKELY(not unexpect_eof()))
7340
            {
7341
                return false;
7342
            }
7343
7344
            get_ignore_noop();
7345
            if (JSON_UNLIKELY(current != '#'))
7346
            {
7347
                if (JSON_UNLIKELY(not unexpect_eof()))
7348
                {
7349
                    return false;
7350
                }
7351
                auto last_token = get_token_string();
7352
                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "expected '#' after UBJSON type information; last byte: 0x" + last_token));
7353
            }
7354
7355
            return get_ubjson_size_value(result.first);
7356
        }
7357
        else if (current == '#')
7358
        {
7359
            return get_ubjson_size_value(result.first);
7360
        }
7361
        return true;
7362
    }
7363
7364
    /*!
7365
    @param prefix  the previously read or set type prefix
7366
    @return whether value creation completed
7367
    */
7368
    bool get_ubjson_value(const int prefix)
7369
    {
7370
        switch (prefix)
7371
        {
7372
            case std::char_traits<char>::eof():  // EOF
7373
                return unexpect_eof();
7374
7375
            case 'T':  // true
7376
                return sax->boolean(true);
7377
            case 'F':  // false
7378
                return sax->boolean(false);
7379
7380
            case 'Z':  // null
7381
                return sax->null();
7382
7383
            case 'U':
7384
            {
7385
                uint8_t number;
7386
                return get_number(number) and sax->number_unsigned(number);
7387
            }
7388
7389
            case 'i':
7390
            {
7391
                int8_t number;
7392
                return get_number(number) and sax->number_integer(number);
7393
            }
7394
7395
            case 'I':
7396
            {
7397
                int16_t number;
7398
                return get_number(number) and sax->number_integer(number);
7399
            }
7400
7401
            case 'l':
7402
            {
7403
                int32_t number;
7404
                return get_number(number) and sax->number_integer(number);
7405
            }
7406
7407
            case 'L':
7408
            {
7409
                int64_t number;
7410
                return get_number(number) and sax->number_integer(number);
7411
            }
7412
7413
            case 'd':
7414
            {
7415
                float number;
7416
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
7417
            }
7418
7419
            case 'D':
7420
            {
7421
                double number;
7422
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
7423
            }
7424
7425
            case 'C':  // char
7426
            {
7427
                get();
7428
                if (JSON_UNLIKELY(not unexpect_eof()))
7429
                {
7430
                    return false;
7431
                }
7432
                if (JSON_UNLIKELY(current > 127))
7433
                {
7434
                    auto last_token = get_token_string();
7435
                    return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token));
7436
                }
7437
                string_t s(1, static_cast<char>(current));
7438
                return sax->string(s);
7439
            }
7440
7441
            case 'S':  // string
7442
            {
7443
                string_t s;
7444
                return get_ubjson_string(s) and sax->string(s);
7445
            }
7446
7447
            case '[':  // array
7448
                return get_ubjson_array();
7449
7450
            case '{':  // object
7451
                return get_ubjson_object();
7452
7453
            default: // anything else
7454
            {
7455
                auto last_token = get_token_string();
7456
                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading UBJSON; last byte: 0x" + last_token));
7457
            }
7458
        }
7459
    }
7460
7461
    /*!
7462
    @return whether array creation completed
7463
    */
7464
    bool get_ubjson_array()
7465
    {
7466
        std::pair<std::size_t, int> size_and_type;
7467
        if (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type)))
7468
        {
7469
            return false;
7470
        }
7471
7472
        if (size_and_type.first != string_t::npos)
7473
        {
7474
            if (JSON_UNLIKELY(not sax->start_array(size_and_type.first)))
7475
            {
7476
                return false;
7477
            }
7478
7479
            if (size_and_type.second != 0)
7480
            {
7481
                if (size_and_type.second != 'N')
7482
                {
7483
                    for (std::size_t i = 0; i < size_and_type.first; ++i)
7484
                    {
7485
                        if (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second)))
7486
                        {
7487
                            return false;
7488
                        }
7489
                    }
7490
                }
7491
            }
7492
            else
7493
            {
7494
                for (std::size_t i = 0; i < size_and_type.first; ++i)
7495
                {
7496
                    if (JSON_UNLIKELY(not parse_ubjson_internal()))
7497
                    {
7498
                        return false;
7499
                    }
7500
                }
7501
            }
7502
        }
7503
        else
7504
        {
7505
            if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
7506
            {
7507
                return false;
7508
            }
7509
7510
            while (current != ']')
7511
            {
7512
                if (JSON_UNLIKELY(not parse_ubjson_internal(false)))
7513
                {
7514
                    return false;
7515
                }
7516
                get_ignore_noop();
7517
            }
7518
        }
7519
7520
        return sax->end_array();
7521
    }
7522
7523
    /*!
7524
    @return whether object creation completed
7525
    */
7526
    bool get_ubjson_object()
7527
    {
7528
        std::pair<std::size_t, int> size_and_type;
7529
        if (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type)))
7530
        {
7531
            return false;
7532
        }
7533
7534
        string_t key;
7535
        if (size_and_type.first != string_t::npos)
7536
        {
7537
            if (JSON_UNLIKELY(not sax->start_object(size_and_type.first)))
7538
            {
7539
                return false;
7540
            }
7541
7542
            if (size_and_type.second != 0)
7543
            {
7544
                for (std::size_t i = 0; i < size_and_type.first; ++i)
7545
                {
7546
                    if (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))
7547
                    {
7548
                        return false;
7549
                    }
7550
                    if (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second)))
7551
                    {
7552
                        return false;
7553
                    }
7554
                    key.clear();
7555
                }
7556
            }
7557
            else
7558
            {
7559
                for (std::size_t i = 0; i < size_and_type.first; ++i)
7560
                {
7561
                    if (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))
7562
                    {
7563
                        return false;
7564
                    }
7565
                    if (JSON_UNLIKELY(not parse_ubjson_internal()))
7566
                    {
7567
                        return false;
7568
                    }
7569
                    key.clear();
7570
                }
7571
            }
7572
        }
7573
        else
7574
        {
7575
            if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
7576
            {
7577
                return false;
7578
            }
7579
7580
            while (current != '}')
7581
            {
7582
                if (JSON_UNLIKELY(not get_ubjson_string(key, false) or not sax->key(key)))
7583
                {
7584
                    return false;
7585
                }
7586
                if (JSON_UNLIKELY(not parse_ubjson_internal()))
7587
                {
7588
                    return false;
7589
                }
7590
                get_ignore_noop();
7591
                key.clear();
7592
            }
7593
        }
7594
7595
        return sax->end_object();
7596
    }
7597
7598
    /*!
7599
    @return whether the last read character is not EOF
7600
    */
7601
    bool unexpect_eof() const
7602
    {
7603
        if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
7604
        {
7605
            return sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, "unexpected end of input"));
7606
        }
7607
        return true;
7608
    }
7609
7610
    /*!
7611
    @return a string representation of the last read byte
7612
    */
7613
    std::string get_token_string() const
7614
    {
7615
        char cr[3];
7616
        snprintf(cr, 3, "%.2hhX", static_cast<unsigned char>(current));
7617
        return std::string{cr};
7618
    }
7619
7620
  private:
7621
    /// input adapter
7622
    input_adapter_t ia = nullptr;
7623
7624
    /// the current character
7625
    int current = std::char_traits<char>::eof();
7626
7627
    /// the number of characters read
7628
    std::size_t chars_read = 0;
7629
7630
    /// whether we can assume little endianess
7631
    const bool is_little_endian = little_endianess();
7632
7633
    /// the SAX parser
7634
    json_sax_t* sax = nullptr;
7635
};
7636
}
7637
}
7638
7639
// #include <nlohmann/detail/output/binary_writer.hpp>
7640
7641
7642
#include <algorithm> // reverse
7643
#include <array> // array
7644
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
7645
#include <cstring> // memcpy
7646
#include <limits> // numeric_limits
7647
7648
// #include <nlohmann/detail/input/binary_reader.hpp>
7649
7650
// #include <nlohmann/detail/output/output_adapters.hpp>
7651
7652
7653
namespace nlohmann
7654
{
7655
namespace detail
7656
{
7657
///////////////////
7658
// binary writer //
7659
///////////////////
7660
7661
/*!
7662
@brief serialization to CBOR and MessagePack values
7663
*/
7664
template<typename BasicJsonType, typename CharType>
7665
class binary_writer
7666
{
7667
  public:
7668
    /*!
7669
    @brief create a binary writer
7670
7671
    @param[in] adapter  output adapter to write to
7672
    */
7673
    explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)
7674
    {
7675
        assert(oa);
7676
    }
7677
7678
    /*!
7679
    @brief[in] j  JSON value to serialize
7680
    */
7681
    void write_cbor(const BasicJsonType& j)
7682
    {
7683
        switch (j.type())
7684
        {
7685
            case value_t::null:
7686
            {
7687
                oa->write_character(static_cast<CharType>(0xF6));
7688
                break;
7689
            }
7690
7691
            case value_t::boolean:
7692
            {
7693
                oa->write_character(j.m_value.boolean
7694
                                    ? static_cast<CharType>(0xF5)
7695
                                    : static_cast<CharType>(0xF4));
7696
                break;
7697
            }
7698
7699
            case value_t::number_integer:
7700
            {
7701
                if (j.m_value.number_integer >= 0)
7702
                {
7703
                    // CBOR does not differentiate between positive signed
7704
                    // integers and unsigned integers. Therefore, we used the
7705
                    // code from the value_t::number_unsigned case here.
7706
                    if (j.m_value.number_integer <= 0x17)
7707
                    {
7708
                        write_number(static_cast<uint8_t>(j.m_value.number_integer));
7709
                    }
7710
                    else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
7711
                    {
7712
                        oa->write_character(static_cast<CharType>(0x18));
7713
                        write_number(static_cast<uint8_t>(j.m_value.number_integer));
7714
                    }
7715
                    else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)())
7716
                    {
7717
                        oa->write_character(static_cast<CharType>(0x19));
7718
                        write_number(static_cast<uint16_t>(j.m_value.number_integer));
7719
                    }
7720
                    else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)())
7721
                    {
7722
                        oa->write_character(static_cast<CharType>(0x1A));
7723
                        write_number(static_cast<uint32_t>(j.m_value.number_integer));
7724
                    }
7725
                    else
7726
                    {
7727
                        oa->write_character(static_cast<CharType>(0x1B));
7728
                        write_number(static_cast<uint64_t>(j.m_value.number_integer));
7729
                    }
7730
                }
7731
                else
7732
                {
7733
                    // The conversions below encode the sign in the first
7734
                    // byte, and the value is converted to a positive number.
7735
                    const auto positive_number = -1 - j.m_value.number_integer;
7736
                    if (j.m_value.number_integer >= -24)
7737
                    {
7738
                        write_number(static_cast<uint8_t>(0x20 + positive_number));
7739
                    }
7740
                    else if (positive_number <= (std::numeric_limits<uint8_t>::max)())
7741
                    {
7742
                        oa->write_character(static_cast<CharType>(0x38));
7743
                        write_number(static_cast<uint8_t>(positive_number));
7744
                    }
7745
                    else if (positive_number <= (std::numeric_limits<uint16_t>::max)())
7746
                    {
7747
                        oa->write_character(static_cast<CharType>(0x39));
7748
                        write_number(static_cast<uint16_t>(positive_number));
7749
                    }
7750
                    else if (positive_number <= (std::numeric_limits<uint32_t>::max)())
7751
                    {
7752
                        oa->write_character(static_cast<CharType>(0x3A));
7753
                        write_number(static_cast<uint32_t>(positive_number));
7754
                    }
7755
                    else
7756
                    {
7757
                        oa->write_character(static_cast<CharType>(0x3B));
7758
                        write_number(static_cast<uint64_t>(positive_number));
7759
                    }
7760
                }
7761
                break;
7762
            }
7763
7764
            case value_t::number_unsigned:
7765
            {
7766
                if (j.m_value.number_unsigned <= 0x17)
7767
                {
7768
                    write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
7769
                }
7770
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
7771
                {
7772
                    oa->write_character(static_cast<CharType>(0x18));
7773
                    write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
7774
                }
7775
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
7776
                {
7777
                    oa->write_character(static_cast<CharType>(0x19));
7778
                    write_number(static_cast<uint16_t>(j.m_value.number_unsigned));
7779
                }
7780
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
7781
                {
7782
                    oa->write_character(static_cast<CharType>(0x1A));
7783
                    write_number(static_cast<uint32_t>(j.m_value.number_unsigned));
7784
                }
7785
                else
7786
                {
7787
                    oa->write_character(static_cast<CharType>(0x1B));
7788
                    write_number(static_cast<uint64_t>(j.m_value.number_unsigned));
7789
                }
7790
                break;
7791
            }
7792
7793
            case value_t::number_float:
7794
            {
7795
                oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
7796
                write_number(j.m_value.number_float);
7797
                break;
7798
            }
7799
7800
            case value_t::string:
7801
            {
7802
                // step 1: write control byte and the string length
7803
                const auto N = j.m_value.string->size();
7804
                if (N <= 0x17)
7805
                {
7806
                    write_number(static_cast<uint8_t>(0x60 + N));
7807
                }
7808
                else if (N <= (std::numeric_limits<uint8_t>::max)())
7809
                {
7810
                    oa->write_character(static_cast<CharType>(0x78));
7811
                    write_number(static_cast<uint8_t>(N));
7812
                }
7813
                else if (N <= (std::numeric_limits<uint16_t>::max)())
7814
                {
7815
                    oa->write_character(static_cast<CharType>(0x79));
7816
                    write_number(static_cast<uint16_t>(N));
7817
                }
7818
                else if (N <= (std::numeric_limits<uint32_t>::max)())
7819
                {
7820
                    oa->write_character(static_cast<CharType>(0x7A));
7821
                    write_number(static_cast<uint32_t>(N));
7822
                }
7823
                // LCOV_EXCL_START
7824
                else if (N <= (std::numeric_limits<uint64_t>::max)())
7825
                {
7826
                    oa->write_character(static_cast<CharType>(0x7B));
7827
                    write_number(static_cast<uint64_t>(N));
7828
                }
7829
                // LCOV_EXCL_STOP
7830
7831
                // step 2: write the string
7832
                oa->write_characters(
7833
                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
7834
                    j.m_value.string->size());
7835
                break;
7836
            }
7837
7838
            case value_t::array:
7839
            {
7840
                // step 1: write control byte and the array size
7841
                const auto N = j.m_value.array->size();
7842
                if (N <= 0x17)
7843
                {
7844
                    write_number(static_cast<uint8_t>(0x80 + N));
7845
                }
7846
                else if (N <= (std::numeric_limits<uint8_t>::max)())
7847
                {
7848
                    oa->write_character(static_cast<CharType>(0x98));
7849
                    write_number(static_cast<uint8_t>(N));
7850
                }
7851
                else if (N <= (std::numeric_limits<uint16_t>::max)())
7852
                {
7853
                    oa->write_character(static_cast<CharType>(0x99));
7854
                    write_number(static_cast<uint16_t>(N));
7855
                }
7856
                else if (N <= (std::numeric_limits<uint32_t>::max)())
7857
                {
7858
                    oa->write_character(static_cast<CharType>(0x9A));
7859
                    write_number(static_cast<uint32_t>(N));
7860
                }
7861
                // LCOV_EXCL_START
7862
                else if (N <= (std::numeric_limits<uint64_t>::max)())
7863
                {
7864
                    oa->write_character(static_cast<CharType>(0x9B));
7865
                    write_number(static_cast<uint64_t>(N));
7866
                }
7867
                // LCOV_EXCL_STOP
7868
7869
                // step 2: write each element
7870
                for (const auto& el : *j.m_value.array)
7871
                {
7872
                    write_cbor(el);
7873
                }
7874
                break;
7875
            }
7876
7877
            case value_t::object:
7878
            {
7879
                // step 1: write control byte and the object size
7880
                const auto N = j.m_value.object->size();
7881
                if (N <= 0x17)
7882
                {
7883
                    write_number(static_cast<uint8_t>(0xA0 + N));
7884
                }
7885
                else if (N <= (std::numeric_limits<uint8_t>::max)())
7886
                {
7887
                    oa->write_character(static_cast<CharType>(0xB8));
7888
                    write_number(static_cast<uint8_t>(N));
7889
                }
7890
                else if (N <= (std::numeric_limits<uint16_t>::max)())
7891
                {
7892
                    oa->write_character(static_cast<CharType>(0xB9));
7893
                    write_number(static_cast<uint16_t>(N));
7894
                }
7895
                else if (N <= (std::numeric_limits<uint32_t>::max)())
7896
                {
7897
                    oa->write_character(static_cast<CharType>(0xBA));
7898
                    write_number(static_cast<uint32_t>(N));
7899
                }
7900
                // LCOV_EXCL_START
7901
                else if (N <= (std::numeric_limits<uint64_t>::max)())
7902
                {
7903
                    oa->write_character(static_cast<CharType>(0xBB));
7904
                    write_number(static_cast<uint64_t>(N));
7905
                }
7906
                // LCOV_EXCL_STOP
7907
7908
                // step 2: write each element
7909
                for (const auto& el : *j.m_value.object)
7910
                {
7911
                    write_cbor(el.first);
7912
                    write_cbor(el.second);
7913
                }
7914
                break;
7915
            }
7916
7917
            default:
7918
                break;
7919
        }
7920
    }
7921
7922
    /*!
7923
    @brief[in] j  JSON value to serialize
7924
    */
7925
    void write_msgpack(const BasicJsonType& j)
7926
    {
7927
        switch (j.type())
7928
        {
7929
            case value_t::null: // nil
7930
            {
7931
                oa->write_character(static_cast<CharType>(0xC0));
7932
                break;
7933
            }
7934
7935
            case value_t::boolean: // true and false
7936
            {
7937
                oa->write_character(j.m_value.boolean
7938
                                    ? static_cast<CharType>(0xC3)
7939
                                    : static_cast<CharType>(0xC2));
7940
                break;
7941
            }
7942
7943
            case value_t::number_integer:
7944
            {
7945
                if (j.m_value.number_integer >= 0)
7946
                {
7947
                    // MessagePack does not differentiate between positive
7948
                    // signed integers and unsigned integers. Therefore, we used
7949
                    // the code from the value_t::number_unsigned case here.
7950
                    if (j.m_value.number_unsigned < 128)
7951
                    {
7952
                        // positive fixnum
7953
                        write_number(static_cast<uint8_t>(j.m_value.number_integer));
7954
                    }
7955
                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
7956
                    {
7957
                        // uint 8
7958
                        oa->write_character(static_cast<CharType>(0xCC));
7959
                        write_number(static_cast<uint8_t>(j.m_value.number_integer));
7960
                    }
7961
                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
7962
                    {
7963
                        // uint 16
7964
                        oa->write_character(static_cast<CharType>(0xCD));
7965
                        write_number(static_cast<uint16_t>(j.m_value.number_integer));
7966
                    }
7967
                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
7968
                    {
7969
                        // uint 32
7970
                        oa->write_character(static_cast<CharType>(0xCE));
7971
                        write_number(static_cast<uint32_t>(j.m_value.number_integer));
7972
                    }
7973
                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
7974
                    {
7975
                        // uint 64
7976
                        oa->write_character(static_cast<CharType>(0xCF));
7977
                        write_number(static_cast<uint64_t>(j.m_value.number_integer));
7978
                    }
7979
                }
7980
                else
7981
                {
7982
                    if (j.m_value.number_integer >= -32)
7983
                    {
7984
                        // negative fixnum
7985
                        write_number(static_cast<int8_t>(j.m_value.number_integer));
7986
                    }
7987
                    else if (j.m_value.number_integer >= (std::numeric_limits<int8_t>::min)() and
7988
                             j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
7989
                    {
7990
                        // int 8
7991
                        oa->write_character(static_cast<CharType>(0xD0));
7992
                        write_number(static_cast<int8_t>(j.m_value.number_integer));
7993
                    }
7994
                    else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and
7995
                             j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
7996
                    {
7997
                        // int 16
7998
                        oa->write_character(static_cast<CharType>(0xD1));
7999
                        write_number(static_cast<int16_t>(j.m_value.number_integer));
8000
                    }
8001
                    else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and
8002
                             j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
8003
                    {
8004
                        // int 32
8005
                        oa->write_character(static_cast<CharType>(0xD2));
8006
                        write_number(static_cast<int32_t>(j.m_value.number_integer));
8007
                    }
8008
                    else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and
8009
                             j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())
8010
                    {
8011
                        // int 64
8012
                        oa->write_character(static_cast<CharType>(0xD3));
8013
                        write_number(static_cast<int64_t>(j.m_value.number_integer));
8014
                    }
8015
                }
8016
                break;
8017
            }
8018
8019
            case value_t::number_unsigned:
8020
            {
8021
                if (j.m_value.number_unsigned < 128)
8022
                {
8023
                    // positive fixnum
8024
                    write_number(static_cast<uint8_t>(j.m_value.number_integer));
8025
                }
8026
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
8027
                {
8028
                    // uint 8
8029
                    oa->write_character(static_cast<CharType>(0xCC));
8030
                    write_number(static_cast<uint8_t>(j.m_value.number_integer));
8031
                }
8032
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
8033
                {
8034
                    // uint 16
8035
                    oa->write_character(static_cast<CharType>(0xCD));
8036
                    write_number(static_cast<uint16_t>(j.m_value.number_integer));
8037
                }
8038
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
8039
                {
8040
                    // uint 32
8041
                    oa->write_character(static_cast<CharType>(0xCE));
8042
                    write_number(static_cast<uint32_t>(j.m_value.number_integer));
8043
                }
8044
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
8045
                {
8046
                    // uint 64
8047
                    oa->write_character(static_cast<CharType>(0xCF));
8048
                    write_number(static_cast<uint64_t>(j.m_value.number_integer));
8049
                }
8050
                break;
8051
            }
8052
8053
            case value_t::number_float:
8054
            {
8055
                oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));
8056
                write_number(j.m_value.number_float);
8057
                break;
8058
            }
8059
8060
            case value_t::string:
8061
            {
8062
                // step 1: write control byte and the string length
8063
                const auto N = j.m_value.string->size();
8064
                if (N <= 31)
8065
                {
8066
                    // fixstr
8067
                    write_number(static_cast<uint8_t>(0xA0 | N));
8068
                }
8069
                else if (N <= (std::numeric_limits<uint8_t>::max)())
8070
                {
8071
                    // str 8
8072
                    oa->write_character(static_cast<CharType>(0xD9));
8073
                    write_number(static_cast<uint8_t>(N));
8074
                }
8075
                else if (N <= (std::numeric_limits<uint16_t>::max)())
8076
                {
8077
                    // str 16
8078
                    oa->write_character(static_cast<CharType>(0xDA));
8079
                    write_number(static_cast<uint16_t>(N));
8080
                }
8081
                else if (N <= (std::numeric_limits<uint32_t>::max)())
8082
                {
8083
                    // str 32
8084
                    oa->write_character(static_cast<CharType>(0xDB));
8085
                    write_number(static_cast<uint32_t>(N));
8086
                }
8087
8088
                // step 2: write the string
8089
                oa->write_characters(
8090
                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
8091
                    j.m_value.string->size());
8092
                break;
8093
            }
8094
8095
            case value_t::array:
8096
            {
8097
                // step 1: write control byte and the array size
8098
                const auto N = j.m_value.array->size();
8099
                if (N <= 15)
8100
                {
8101
                    // fixarray
8102
                    write_number(static_cast<uint8_t>(0x90 | N));
8103
                }
8104
                else if (N <= (std::numeric_limits<uint16_t>::max)())
8105
                {
8106
                    // array 16
8107
                    oa->write_character(static_cast<CharType>(0xDC));
8108
                    write_number(static_cast<uint16_t>(N));
8109
                }
8110
                else if (N <= (std::numeric_limits<uint32_t>::max)())
8111
                {
8112
                    // array 32
8113
                    oa->write_character(static_cast<CharType>(0xDD));
8114
                    write_number(static_cast<uint32_t>(N));
8115
                }
8116
8117
                // step 2: write each element
8118
                for (const auto& el : *j.m_value.array)
8119
                {
8120
                    write_msgpack(el);
8121
                }
8122
                break;
8123
            }
8124
8125
            case value_t::object:
8126
            {
8127
                // step 1: write control byte and the object size
8128
                const auto N = j.m_value.object->size();
8129
                if (N <= 15)
8130
                {
8131
                    // fixmap
8132
                    write_number(static_cast<uint8_t>(0x80 | (N & 0xF)));
8133
                }
8134
                else if (N <= (std::numeric_limits<uint16_t>::max)())
8135
                {
8136
                    // map 16
8137
                    oa->write_character(static_cast<CharType>(0xDE));
8138
                    write_number(static_cast<uint16_t>(N));
8139
                }
8140
                else if (N <= (std::numeric_limits<uint32_t>::max)())
8141
                {
8142
                    // map 32
8143
                    oa->write_character(static_cast<CharType>(0xDF));
8144
                    write_number(static_cast<uint32_t>(N));
8145
                }
8146
8147
                // step 2: write each element
8148
                for (const auto& el : *j.m_value.object)
8149
                {
8150
                    write_msgpack(el.first);
8151
                    write_msgpack(el.second);
8152
                }
8153
                break;
8154
            }
8155
8156
            default:
8157
                break;
8158
        }
8159
    }
8160
8161
    /*!
8162
    @param[in] j  JSON value to serialize
8163
    @param[in] use_count   whether to use '#' prefixes (optimized format)
8164
    @param[in] use_type    whether to use '$' prefixes (optimized format)
8165
    @param[in] add_prefix  whether prefixes need to be used for this value
8166
    */
8167
    void write_ubjson(const BasicJsonType& j, const bool use_count,
8168
                      const bool use_type, const bool add_prefix = true)
8169
    {
8170
        switch (j.type())
8171
        {
8172
            case value_t::null:
8173
            {
8174
                if (add_prefix)
8175
                {
8176
                    oa->write_character(static_cast<CharType>('Z'));
8177
                }
8178
                break;
8179
            }
8180
8181
            case value_t::boolean:
8182
            {
8183
                if (add_prefix)
8184
                    oa->write_character(j.m_value.boolean
8185
                                        ? static_cast<CharType>('T')
8186
                                        : static_cast<CharType>('F'));
8187
                break;
8188
            }
8189
8190
            case value_t::number_integer:
8191
            {
8192
                write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);
8193
                break;
8194
            }
8195
8196
            case value_t::number_unsigned:
8197
            {
8198
                write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);
8199
                break;
8200
            }
8201
8202
            case value_t::number_float:
8203
            {
8204
                write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);
8205
                break;
8206
            }
8207
8208
            case value_t::string:
8209
            {
8210
                if (add_prefix)
8211
                {
8212
                    oa->write_character(static_cast<CharType>('S'));
8213
                }
8214
                write_number_with_ubjson_prefix(j.m_value.string->size(), true);
8215
                oa->write_characters(
8216
                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
8217
                    j.m_value.string->size());
8218
                break;
8219
            }
8220
8221
            case value_t::array:
8222
            {
8223
                if (add_prefix)
8224
                {
8225
                    oa->write_character(static_cast<CharType>('['));
8226
                }
8227
8228
                bool prefix_required = true;
8229
                if (use_type and not j.m_value.array->empty())
8230
                {
8231
                    assert(use_count);
8232
                    const CharType first_prefix = ubjson_prefix(j.front());
8233
                    const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
8234
                                                         [this, first_prefix](const BasicJsonType & v)
8235
                    {
8236
                        return ubjson_prefix(v) == first_prefix;
8237
                    });
8238
8239
                    if (same_prefix)
8240
                    {
8241
                        prefix_required = false;
8242
                        oa->write_character(static_cast<CharType>('$'));
8243
                        oa->write_character(first_prefix);
8244
                    }
8245
                }
8246
8247
                if (use_count)
8248
                {
8249
                    oa->write_character(static_cast<CharType>('#'));
8250
                    write_number_with_ubjson_prefix(j.m_value.array->size(), true);
8251
                }
8252
8253
                for (const auto& el : *j.m_value.array)
8254
                {
8255
                    write_ubjson(el, use_count, use_type, prefix_required);
8256
                }
8257
8258
                if (not use_count)
8259
                {
8260
                    oa->write_character(static_cast<CharType>(']'));
8261
                }
8262
8263
                break;
8264
            }
8265
8266
            case value_t::object:
8267
            {
8268
                if (add_prefix)
8269
                {
8270
                    oa->write_character(static_cast<CharType>('{'));
8271
                }
8272
8273
                bool prefix_required = true;
8274
                if (use_type and not j.m_value.object->empty())
8275
                {
8276
                    assert(use_count);
8277
                    const CharType first_prefix = ubjson_prefix(j.front());
8278
                    const bool same_prefix = std::all_of(j.begin(), j.end(),
8279
                                                         [this, first_prefix](const BasicJsonType & v)
8280
                    {
8281
                        return ubjson_prefix(v) == first_prefix;
8282
                    });
8283
8284
                    if (same_prefix)
8285
                    {
8286
                        prefix_required = false;
8287
                        oa->write_character(static_cast<CharType>('$'));
8288
                        oa->write_character(first_prefix);
8289
                    }
8290
                }
8291
8292
                if (use_count)
8293
                {
8294
                    oa->write_character(static_cast<CharType>('#'));
8295
                    write_number_with_ubjson_prefix(j.m_value.object->size(), true);
8296
                }
8297
8298
                for (const auto& el : *j.m_value.object)
8299
                {
8300
                    write_number_with_ubjson_prefix(el.first.size(), true);
8301
                    oa->write_characters(
8302
                        reinterpret_cast<const CharType*>(el.first.c_str()),
8303
                        el.first.size());
8304
                    write_ubjson(el.second, use_count, use_type, prefix_required);
8305
                }
8306
8307
                if (not use_count)
8308
                {
8309
                    oa->write_character(static_cast<CharType>('}'));
8310
                }
8311
8312
                break;
8313
            }
8314
8315
            default:
8316
                break;
8317
        }
8318
    }
8319
8320
  private:
8321
    /*
8322
    @brief write a number to output input
8323
8324
    @param[in] n number of type @a NumberType
8325
    @tparam NumberType the type of the number
8326
8327
    @note This function needs to respect the system's endianess, because bytes
8328
          in CBOR, MessagePack, and UBJSON are stored in network order (big
8329
          endian) and therefore need reordering on little endian systems.
8330
    */
8331
    template<typename NumberType>
8332
    void write_number(const NumberType n)
8333
    {
8334
        // step 1: write number to array of length NumberType
8335
        std::array<CharType, sizeof(NumberType)> vec;
8336
        std::memcpy(vec.data(), &n, sizeof(NumberType));
8337
8338
        // step 2: write array to output (with possible reordering)
8339
        if (is_little_endian)
8340
        {
8341
            // reverse byte order prior to conversion if necessary
8342
            std::reverse(vec.begin(), vec.end());
8343
        }
8344
8345
        oa->write_characters(vec.data(), sizeof(NumberType));
8346
    }
8347
8348
    // UBJSON: write number (floating point)
8349
    template<typename NumberType, typename std::enable_if<
8350
                 std::is_floating_point<NumberType>::value, int>::type = 0>
8351
    void write_number_with_ubjson_prefix(const NumberType n,
8352
                                         const bool add_prefix)
8353
    {
8354
        if (add_prefix)
8355
        {
8356
            oa->write_character(get_ubjson_float_prefix(n));
8357
        }
8358
        write_number(n);
8359
    }
8360
8361
    // UBJSON: write number (unsigned integer)
8362
    template<typename NumberType, typename std::enable_if<
8363
                 std::is_unsigned<NumberType>::value, int>::type = 0>
8364
    void write_number_with_ubjson_prefix(const NumberType n,
8365
                                         const bool add_prefix)
8366
    {
8367
        if (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
8368
        {
8369
            if (add_prefix)
8370
            {
8371
                oa->write_character(static_cast<CharType>('i'));  // int8
8372
            }
8373
            write_number(static_cast<uint8_t>(n));
8374
        }
8375
        else if (n <= (std::numeric_limits<uint8_t>::max)())
8376
        {
8377
            if (add_prefix)
8378
            {
8379
                oa->write_character(static_cast<CharType>('U'));  // uint8
8380
            }
8381
            write_number(static_cast<uint8_t>(n));
8382
        }
8383
        else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
8384
        {
8385
            if (add_prefix)
8386
            {
8387
                oa->write_character(static_cast<CharType>('I'));  // int16
8388
            }
8389
            write_number(static_cast<int16_t>(n));
8390
        }
8391
        else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
8392
        {
8393
            if (add_prefix)
8394
            {
8395
                oa->write_character(static_cast<CharType>('l'));  // int32
8396
            }
8397
            write_number(static_cast<int32_t>(n));
8398
        }
8399
        else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
8400
        {
8401
            if (add_prefix)
8402
            {
8403
                oa->write_character(static_cast<CharType>('L'));  // int64
8404
            }
8405
            write_number(static_cast<int64_t>(n));
8406
        }
8407
        else
8408
        {
8409
            JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
8410
        }
8411
    }
8412
8413
    // UBJSON: write number (signed integer)
8414
    template<typename NumberType, typename std::enable_if<
8415
                 std::is_signed<NumberType>::value and
8416
                 not std::is_floating_point<NumberType>::value, int>::type = 0>
8417
    void write_number_with_ubjson_prefix(const NumberType n,
8418
                                         const bool add_prefix)
8419
    {
8420
        if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
8421
        {
8422
            if (add_prefix)
8423
            {
8424
                oa->write_character(static_cast<CharType>('i'));  // int8
8425
            }
8426
            write_number(static_cast<int8_t>(n));
8427
        }
8428
        else if (static_cast<int64_t>((std::numeric_limits<uint8_t>::min)()) <= n and n <= static_cast<int64_t>((std::numeric_limits<uint8_t>::max)()))
8429
        {
8430
            if (add_prefix)
8431
            {
8432
                oa->write_character(static_cast<CharType>('U'));  // uint8
8433
            }
8434
            write_number(static_cast<uint8_t>(n));
8435
        }
8436
        else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())
8437
        {
8438
            if (add_prefix)
8439
            {
8440
                oa->write_character(static_cast<CharType>('I'));  // int16
8441
            }
8442
            write_number(static_cast<int16_t>(n));
8443
        }
8444
        else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
8445
        {
8446
            if (add_prefix)
8447
            {
8448
                oa->write_character(static_cast<CharType>('l'));  // int32
8449
            }
8450
            write_number(static_cast<int32_t>(n));
8451
        }
8452
        else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())
8453
        {
8454
            if (add_prefix)
8455
            {
8456
                oa->write_character(static_cast<CharType>('L'));  // int64
8457
            }
8458
            write_number(static_cast<int64_t>(n));
8459
        }
8460
        // LCOV_EXCL_START
8461
        else
8462
        {
8463
            JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
8464
        }
8465
        // LCOV_EXCL_STOP
8466
    }
8467
8468
    /*!
8469
    @brief determine the type prefix of container values
8470
8471
    @note This function does not need to be 100% accurate when it comes to
8472
          integer limits. In case a number exceeds the limits of int64_t,
8473
          this will be detected by a later call to function
8474
          write_number_with_ubjson_prefix. Therefore, we return 'L' for any
8475
          value that does not fit the previous limits.
8476
    */
8477
    CharType ubjson_prefix(const BasicJsonType& j) const noexcept
8478
    {
8479
        switch (j.type())
8480
        {
8481
            case value_t::null:
8482
                return 'Z';
8483
8484
            case value_t::boolean:
8485
                return j.m_value.boolean ? 'T' : 'F';
8486
8487
            case value_t::number_integer:
8488
            {
8489
                if ((std::numeric_limits<int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
8490
                {
8491
                    return 'i';
8492
                }
8493
                else if ((std::numeric_limits<uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
8494
                {
8495
                    return 'U';
8496
                }
8497
                else if ((std::numeric_limits<int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
8498
                {
8499
                    return 'I';
8500
                }
8501
                else if ((std::numeric_limits<int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
8502
                {
8503
                    return 'l';
8504
                }
8505
                else  // no check and assume int64_t (see note above)
8506
                {
8507
                    return 'L';
8508
                }
8509
            }
8510
8511
            case value_t::number_unsigned:
8512
            {
8513
                if (j.m_value.number_unsigned <= (std::numeric_limits<int8_t>::max)())
8514
                {
8515
                    return 'i';
8516
                }
8517
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
8518
                {
8519
                    return 'U';
8520
                }
8521
                else if (j.m_value.number_unsigned <= (std::numeric_limits<int16_t>::max)())
8522
                {
8523
                    return 'I';
8524
                }
8525
                else if (j.m_value.number_unsigned <= (std::numeric_limits<int32_t>::max)())
8526
                {
8527
                    return 'l';
8528
                }
8529
                else  // no check and assume int64_t (see note above)
8530
                {
8531
                    return 'L';
8532
                }
8533
            }
8534
8535
            case value_t::number_float:
8536
                return get_ubjson_float_prefix(j.m_value.number_float);
8537
8538
            case value_t::string:
8539
                return 'S';
8540
8541
            case value_t::array:
8542
                return '[';
8543
8544
            case value_t::object:
8545
                return '{';
8546
8547
            default:  // discarded values
8548
                return 'N';
8549
        }
8550
    }
8551
8552
    static constexpr CharType get_cbor_float_prefix(float)
8553
    {
8554
        return static_cast<CharType>(0xFA);  // Single-Precision Float
8555
    }
8556
8557
    static constexpr CharType get_cbor_float_prefix(double)
8558
    {
8559
        return static_cast<CharType>(0xFB);  // Double-Precision Float
8560
    }
8561
8562
    static constexpr CharType get_msgpack_float_prefix(float)
8563
    {
8564
        return static_cast<CharType>(0xCA);  // float 32
8565
    }
8566
8567
    static constexpr CharType get_msgpack_float_prefix(double)
8568
    {
8569
        return static_cast<CharType>(0xCB);  // float 64
8570
    }
8571
8572
    static constexpr CharType get_ubjson_float_prefix(float)
8573
    {
8574
        return 'd';  // float 32
8575
    }
8576
8577
    static constexpr CharType get_ubjson_float_prefix(double)
8578
    {
8579
        return 'D';  // float 64
8580
    }
8581
8582
  private:
8583
    /// whether we can assume little endianess
8584
    const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
8585
8586
    /// the output
8587
    output_adapter_t<CharType> oa = nullptr;
8588
};
8589
}
8590
}
8591
8592
// #include <nlohmann/detail/output/serializer.hpp>
8593
8594
8595
#include <algorithm> // reverse, remove, fill, find, none_of
8596
#include <array> // array
8597
#include <cassert> // assert
8598
#include <ciso646> // and, or
8599
#include <clocale> // localeconv, lconv
8600
#include <cmath> // labs, isfinite, isnan, signbit
8601
#include <cstddef> // size_t, ptrdiff_t
8602
#include <cstdint> // uint8_t
8603
#include <cstdio> // snprintf
8604
#include <limits> // numeric_limits
8605
#include <string> // string
8606
#include <type_traits> // is_same
8607
8608
// #include <nlohmann/detail/exceptions.hpp>
8609
8610
// #include <nlohmann/detail/conversions/to_chars.hpp>
8611
8612
8613
#include <cassert> // assert
8614
#include <ciso646> // or, and, not
8615
#include <cmath>   // signbit, isfinite
8616
#include <cstdint> // intN_t, uintN_t
8617
#include <cstring> // memcpy, memmove
8618
8619
namespace nlohmann
8620
{
8621
namespace detail
8622
{
8623
8624
/*!
8625
@brief implements the Grisu2 algorithm for binary to decimal floating-point
8626
conversion.
8627
8628
This implementation is a slightly modified version of the reference
8629
implementation which may be obtained from
8630
http://florian.loitsch.com/publications (bench.tar.gz).
8631
8632
The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
8633
8634
For a detailed description of the algorithm see:
8635
8636
[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with
8637
    Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming
8638
    Language Design and Implementation, PLDI 2010
8639
[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
8640
    Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
8641
    Design and Implementation, PLDI 1996
8642
*/
8643
namespace dtoa_impl
8644
{
8645
8646
template <typename Target, typename Source>
8647
Target reinterpret_bits(const Source source)
7
8648
{
7
8649
    static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
7
8650
7
8651
    Target target;
7
8652
    std::memcpy(&target, &source, sizeof(Source));
7
8653
    return target;
7
8654
}
8655
8656
struct diyfp // f * 2^e
8657
{
8658
    static constexpr int kPrecision = 64; // = q
8659
8660
    uint64_t f;
8661
    int e;
8662
0
8663
    constexpr diyfp() noexcept : f(0), e(0) {}
91
8664
    constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
8665
8666
    /*!
8667
    @brief returns x - y
8668
    @pre x.e == y.e and x.f >= y.f
8669
    */
8670
    static diyfp sub(const diyfp& x, const diyfp& y) noexcept
14
8671
    {
14
8672
        assert(x.e == y.e);
14
8673
        assert(x.f >= y.f);
14
8674
14
8675
        return diyfp(x.f - y.f, x.e);
14
8676
    }
8677
8678
    /*!
8679
    @brief returns x * y
8680
    @note The result is rounded. (Only the upper q bits are returned.)
8681
    */
8682
    static diyfp mul(const diyfp& x, const diyfp& y) noexcept
21
8683
    {
21
8684
        static_assert(kPrecision == 64, "internal error");
21
8685
21
8686
        // Computes:
21
8687
        //  f = round((x.f * y.f) / 2^q)
21
8688
        //  e = x.e + y.e + q
21
8689
21
8690
        // Emulate the 64-bit * 64-bit multiplication:
21
8691
        //
21
8692
        // p = u * v
21
8693
        //   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)
21
8694
        //   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )
21
8695
        //   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )
21
8696
        //   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )
21
8697
        //   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)
21
8698
        //   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )
21
8699
        //   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )
21
8700
        //
21
8701
        // (Since Q might be larger than 2^32 - 1)
21
8702
        //
21
8703
        //   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)
21
8704
        //
21
8705
        // (Q_hi + H does not overflow a 64-bit int)
21
8706
        //
21
8707
        //   = p_lo + 2^64 p_hi
21
8708
21
8709
        const uint64_t u_lo = x.f & 0xFFFFFFFF;
21
8710
        const uint64_t u_hi = x.f >> 32;
21
8711
        const uint64_t v_lo = y.f & 0xFFFFFFFF;
21
8712
        const uint64_t v_hi = y.f >> 32;
21
8713
21
8714
        const uint64_t p0 = u_lo * v_lo;
21
8715
        const uint64_t p1 = u_lo * v_hi;
21
8716
        const uint64_t p2 = u_hi * v_lo;
21
8717
        const uint64_t p3 = u_hi * v_hi;
21
8718
21
8719
        const uint64_t p0_hi = p0 >> 32;
21
8720
        const uint64_t p1_lo = p1 & 0xFFFFFFFF;
21
8721
        const uint64_t p1_hi = p1 >> 32;
21
8722
        const uint64_t p2_lo = p2 & 0xFFFFFFFF;
21
8723
        const uint64_t p2_hi = p2 >> 32;
21
8724
21
8725
        uint64_t Q = p0_hi + p1_lo + p2_lo;
21
8726
21
8727
        // The full product might now be computed as
21
8728
        //
21
8729
        // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)
21
8730
        // p_lo = p0_lo + (Q << 32)
21
8731
        //
21
8732
        // But in this particular case here, the full p_lo is not required.
21
8733
        // Effectively we only need to add the highest bit in p_lo to p_hi (and
21
8734
        // Q_hi + 1 does not overflow).
21
8735
21
8736
        Q += uint64_t{1} << (64 - 32 - 1); // round, ties up
21
8737
21
8738
        const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32);
21
8739
21
8740
        return diyfp(h, x.e + y.e + 64);
21
8741
    }
8742
8743
    /*!
8744
    @brief normalize x such that the significand is >= 2^(q-1)
8745
    @pre x.f != 0
8746
    */
8747
    static diyfp normalize(diyfp x) noexcept
14
8748
    {
14
8749
        assert(x.f != 0);
14
8750
161
8751
        while ((x.f >> 63) == 0)
147
8752
        {
147
8753
            x.f <<= 1;
147
8754
            x.e--;
147
8755
        }
14
8756
14
8757
        return x;
14
8758
    }
8759
8760
    /*!
8761
    @brief normalize x such that the result has the exponent E
8762
    @pre e >= x.e and the upper e - x.e bits of x.f must be zero.
8763
    */
8764
    static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept
7
8765
    {
7
8766
        const int delta = x.e - target_exponent;
7
8767
7
8768
        assert(delta >= 0);
7
8769
        assert(((x.f << delta) >> delta) == x.f);
7
8770
7
8771
        return diyfp(x.f << delta, target_exponent);
7
8772
    }
8773
};
8774
8775
struct boundaries
8776
{
8777
    diyfp w;
8778
    diyfp minus;
8779
    diyfp plus;
8780
};
8781
8782
/*!
8783
Compute the (normalized) diyfp representing the input number 'value' and its
8784
boundaries.
8785
8786
@pre value must be finite and positive
8787
*/
8788
template <typename FloatType>
8789
boundaries compute_boundaries(FloatType value)
7
8790
{
7
8791
    assert(std::isfinite(value));
7
8792
    assert(value > 0);
7
8793
7
8794
    // Convert the IEEE representation into a diyfp.
7
8795
    //
7
8796
    // If v is denormal:
7
8797
    //      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))
7
8798
    // If v is normalized:
7
8799
    //      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))
7
8800
7
8801
    static_assert(std::numeric_limits<FloatType>::is_iec559,
7
8802
                  "internal error: dtoa_short requires an IEEE-754 floating-point implementation");
7
8803
7
8804
    constexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)
7
8805
    constexpr int      kBias      = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);
7
8806
    constexpr int      kMinExp    = 1 - kBias;
7
8807
    constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1)
7
8808
7
8809
    using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type;
7
8810
7
8811
    const uint64_t bits = reinterpret_bits<bits_type>(value);
7
8812
    const uint64_t E = bits >> (kPrecision - 1);
7
8813
    const uint64_t F = bits & (kHiddenBit - 1);
7
8814
7
8815
    const bool is_denormal = (E == 0);
7
8816
    const diyfp v = is_denormal
0
8817
                    ? diyfp(F, kMinExp)
7
8818
                    : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
7
8819
7
8820
    // Compute the boundaries m- and m+ of the floating-point value
7
8821
    // v = f * 2^e.
7
8822
    //
7
8823
    // Determine v- and v+, the floating-point predecessor and successor if v,
7
8824
    // respectively.
7
8825
    //
7
8826
    //      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)
7
8827
    //         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)
7
8828
    //
7
8829
    //      v+ = v + 2^e
7
8830
    //
7
8831
    // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_
7
8832
    // between m- and m+ round to v, regardless of how the input rounding
7
8833
    // algorithm breaks ties.
7
8834
    //
7
8835
    //      ---+-------------+-------------+-------------+-------------+---  (A)
7
8836
    //         v-            m-            v             m+            v+
7
8837
    //
7
8838
    //      -----------------+------+------+-------------+-------------+---  (B)
7
8839
    //                       v-     m-     v             m+            v+
7
8840
0
8841
    const bool lower_boundary_is_closer = (F == 0 and E > 1);
7
8842
    const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
7
8843
    const diyfp m_minus = lower_boundary_is_closer
0
8844
                          ? diyfp(4 * v.f - 1, v.e - 2)  // (B)
7
8845
                          : diyfp(2 * v.f - 1, v.e - 1); // (A)
7
8846
7
8847
    // Determine the normalized w+ = m+.
7
8848
    const diyfp w_plus = diyfp::normalize(m_plus);
7
8849
7
8850
    // Determine w- = m- such that e_(w-) = e_(w+).
7
8851
    const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);
7
8852
7
8853
    return {diyfp::normalize(v), w_minus, w_plus};
7
8854
}
8855
8856
// Given normalized diyfp w, Grisu needs to find a (normalized) cached
8857
// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies
8858
// within a certain range [alpha, gamma] (Definition 3.2 from [1])
8859
//
8860
//      alpha <= e = e_c + e_w + q <= gamma
8861
//
8862
// or
8863
//
8864
//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q
8865
//                          <= f_c * f_w * 2^gamma
8866
//
8867
// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies
8868
//
8869
//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma
8870
//
8871
// or
8872
//
8873
//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)
8874
//
8875
// The choice of (alpha,gamma) determines the size of the table and the form of
8876
// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well
8877
// in practice:
8878
//
8879
// The idea is to cut the number c * w = f * 2^e into two parts, which can be
8880
// processed independently: An integral part p1, and a fractional part p2:
8881
//
8882
//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e
8883
//              = (f div 2^-e) + (f mod 2^-e) * 2^e
8884
//              = p1 + p2 * 2^e
8885
//
8886
// The conversion of p1 into decimal form requires a series of divisions and
8887
// modulos by (a power of) 10. These operations are faster for 32-bit than for
8888
// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be
8889
// achieved by choosing
8890
//
8891
//      -e >= 32   or   e <= -32 := gamma
8892
//
8893
// In order to convert the fractional part
8894
//
8895
//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...
8896
//
8897
// into decimal form, the fraction is repeatedly multiplied by 10 and the digits
8898
// d[-i] are extracted in order:
8899
//
8900
//      (10 * p2) div 2^-e = d[-1]
8901
//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...
8902
//
8903
// The multiplication by 10 must not overflow. It is sufficient to choose
8904
//
8905
//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.
8906
//
8907
// Since p2 = f mod 2^-e < 2^-e,
8908
//
8909
//      -e <= 60   or   e >= -60 := alpha
8910
8911
constexpr int kAlpha = -60;
8912
constexpr int kGamma = -32;
8913
8914
struct cached_power // c = f * 2^e ~= 10^k
8915
{
8916
    uint64_t f;
8917
    int e;
8918
    int k;
8919
};
8920
8921
/*!
8922
For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached
8923
power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c
8924
satisfies (Definition 3.2 from [1])
8925
8926
     alpha <= e_c + e + q <= gamma.
8927
*/
8928
inline cached_power get_cached_power_for_binary_exponent(int e)
7
8929
{
7
8930
    // Now
7
8931
    //
7
8932
    //      alpha <= e_c + e + q <= gamma                                    (1)
7
8933
    //      ==> f_c * 2^alpha <= c * 2^e * 2^q
7
8934
    //
7
8935
    // and since the c's are normalized, 2^(q-1) <= f_c,
7
8936
    //
7
8937
    //      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)
7
8938
    //      ==> 2^(alpha - e - 1) <= c
7
8939
    //
7
8940
    // If c were an exakt power of ten, i.e. c = 10^k, one may determine k as
7
8941
    //
7
8942
    //      k = ceil( log_10( 2^(alpha - e - 1) ) )
7
8943
    //        = ceil( (alpha - e - 1) * log_10(2) )
7
8944
    //
7
8945
    // From the paper:
7
8946
    // "In theory the result of the procedure could be wrong since c is rounded,
7
8947
    //  and the computation itself is approximated [...]. In practice, however,
7
8948
    //  this simple function is sufficient."
7
8949
    //
7
8950
    // For IEEE double precision floating-point numbers converted into
7
8951
    // normalized diyfp's w = f * 2^e, with q = 64,
7
8952
    //
7
8953
    //      e >= -1022      (min IEEE exponent)
7
8954
    //           -52        (p - 1)
7
8955
    //           -52        (p - 1, possibly normalize denormal IEEE numbers)
7
8956
    //           -11        (normalize the diyfp)
7
8957
    //         = -1137
7
8958
    //
7
8959
    // and
7
8960
    //
7
8961
    //      e <= +1023      (max IEEE exponent)
7
8962
    //           -52        (p - 1)
7
8963
    //           -11        (normalize the diyfp)
7
8964
    //         = 960
7
8965
    //
7
8966
    // This binary exponent range [-1137,960] results in a decimal exponent
7
8967
    // range [-307,324]. One does not need to store a cached power for each
7
8968
    // k in this range. For each such k it suffices to find a cached power
7
8969
    // such that the exponent of the product lies in [alpha,gamma].
7
8970
    // This implies that the difference of the decimal exponents of adjacent
7
8971
    // table entries must be less than or equal to
7
8972
    //
7
8973
    //      floor( (gamma - alpha) * log_10(2) ) = 8.
7
8974
    //
7
8975
    // (A smaller distance gamma-alpha would require a larger table.)
7
8976
7
8977
    // NB:
7
8978
    // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
7
8979
7
8980
    constexpr int kCachedPowersSize = 79;
7
8981
    constexpr int kCachedPowersMinDecExp = -300;
7
8982
    constexpr int kCachedPowersDecStep = 8;
7
8983
7
8984
    static constexpr cached_power kCachedPowers[] =
7
8985
    {
7
8986
        { 0xAB70FE17C79AC6CA, -1060, -300 },
7
8987
        { 0xFF77B1FCBEBCDC4F, -1034, -292 },
7
8988
        { 0xBE5691EF416BD60C, -1007, -284 },
7
8989
        { 0x8DD01FAD907FFC3C,  -980, -276 },
7
8990
        { 0xD3515C2831559A83,  -954, -268 },
7
8991
        { 0x9D71AC8FADA6C9B5,  -927, -260 },
7
8992
        { 0xEA9C227723EE8BCB,  -901, -252 },
7
8993
        { 0xAECC49914078536D,  -874, -244 },
7
8994
        { 0x823C12795DB6CE57,  -847, -236 },
7
8995
        { 0xC21094364DFB5637,  -821, -228 },
7
8996
        { 0x9096EA6F3848984F,  -794, -220 },
7
8997
        { 0xD77485CB25823AC7,  -768, -212 },
7
8998
        { 0xA086CFCD97BF97F4,  -741, -204 },
7
8999
        { 0xEF340A98172AACE5,  -715, -196 },
7
9000
        { 0xB23867FB2A35B28E,  -688, -188 },
7
9001
        { 0x84C8D4DFD2C63F3B,  -661, -180 },
7
9002
        { 0xC5DD44271AD3CDBA,  -635, -172 },
7
9003
        { 0x936B9FCEBB25C996,  -608, -164 },
7
9004
        { 0xDBAC6C247D62A584,  -582, -156 },
7
9005
        { 0xA3AB66580D5FDAF6,  -555, -148 },
7
9006
        { 0xF3E2F893DEC3F126,  -529, -140 },
7
9007
        { 0xB5B5ADA8AAFF80B8,  -502, -132 },
7
9008
        { 0x87625F056C7C4A8B,  -475, -124 },
7
9009
        { 0xC9BCFF6034C13053,  -449, -116 },
7
9010
        { 0x964E858C91BA2655,  -422, -108 },
7
9011
        { 0xDFF9772470297EBD,  -396, -100 },
7
9012
        { 0xA6DFBD9FB8E5B88F,  -369,  -92 },
7
9013
        { 0xF8A95FCF88747D94,  -343,  -84 },
7
9014
        { 0xB94470938FA89BCF,  -316,  -76 },
7
9015
        { 0x8A08F0F8BF0F156B,  -289,  -68 },
7
9016
        { 0xCDB02555653131B6,  -263,  -60 },
7
9017
        { 0x993FE2C6D07B7FAC,  -236,  -52 },
7
9018
        { 0xE45C10C42A2B3B06,  -210,  -44 },
7
9019
        { 0xAA242499697392D3,  -183,  -36 },
7
9020
        { 0xFD87B5F28300CA0E,  -157,  -28 },
7
9021
        { 0xBCE5086492111AEB,  -130,  -20 },
7
9022
        { 0x8CBCCC096F5088CC,  -103,  -12 },
7
9023
        { 0xD1B71758E219652C,   -77,   -4 },
7
9024
        { 0x9C40000000000000,   -50,    4 },
7
9025
        { 0xE8D4A51000000000,   -24,   12 },
7
9026
        { 0xAD78EBC5AC620000,     3,   20 },
7
9027
        { 0x813F3978F8940984,    30,   28 },
7
9028
        { 0xC097CE7BC90715B3,    56,   36 },
7
9029
        { 0x8F7E32CE7BEA5C70,    83,   44 },
7
9030
        { 0xD5D238A4ABE98068,   109,   52 },
7
9031
        { 0x9F4F2726179A2245,   136,   60 },
7
9032
        { 0xED63A231D4C4FB27,   162,   68 },
7
9033
        { 0xB0DE65388CC8ADA8,   189,   76 },
7
9034
        { 0x83C7088E1AAB65DB,   216,   84 },
7
9035
        { 0xC45D1DF942711D9A,   242,   92 },
7
9036
        { 0x924D692CA61BE758,   269,  100 },
7
9037
        { 0xDA01EE641A708DEA,   295,  108 },
7
9038
        { 0xA26DA3999AEF774A,   322,  116 },
7
9039
        { 0xF209787BB47D6B85,   348,  124 },
7
9040
        { 0xB454E4A179DD1877,   375,  132 },
7
9041
        { 0x865B86925B9BC5C2,   402,  140 },
7
9042
        { 0xC83553C5C8965D3D,   428,  148 },
7
9043
        { 0x952AB45CFA97A0B3,   455,  156 },
7
9044
        { 0xDE469FBD99A05FE3,   481,  164 },
7
9045
        { 0xA59BC234DB398C25,   508,  172 },
7
9046
        { 0xF6C69A72A3989F5C,   534,  180 },
7
9047
        { 0xB7DCBF5354E9BECE,   561,  188 },
7
9048
        { 0x88FCF317F22241E2,   588,  196 },
7
9049
        { 0xCC20CE9BD35C78A5,   614,  204 },
7
9050
        { 0x98165AF37B2153DF,   641,  212 },
7
9051
        { 0xE2A0B5DC971F303A,   667,  220 },
7
9052
        { 0xA8D9D1535CE3B396,   694,  228 },
7
9053
        { 0xFB9B7CD9A4A7443C,   720,  236 },
7
9054
        { 0xBB764C4CA7A44410,   747,  244 },
7
9055
        { 0x8BAB8EEFB6409C1A,   774,  252 },
7
9056
        { 0xD01FEF10A657842C,   800,  260 },
7
9057
        { 0x9B10A4E5E9913129,   827,  268 },
7
9058
        { 0xE7109BFBA19C0C9D,   853,  276 },
7
9059
        { 0xAC2820D9623BF429,   880,  284 },
7
9060
        { 0x80444B5E7AA7CF85,   907,  292 },
7
9061
        { 0xBF21E44003ACDD2D,   933,  300 },
7
9062
        { 0x8E679C2F5E44FF8F,   960,  308 },
7
9063
        { 0xD433179D9C8CB841,   986,  316 },
7
9064
        { 0x9E19DB92B4E31BA9,  1013,  324 },
7
9065
    };
7
9066
7
9067
    // This computation gives exactly the same results for k as
7
9068
    //      k = ceil((kAlpha - e - 1) * 0.30102999566398114)
7
9069
    // for |e| <= 1500, but doesn't require floating-point operations.
7
9070
    // NB: log_10(2) ~= 78913 / 2^18
7
9071
    assert(e >= -1500);
7
9072
    assert(e <=  1500);
7
9073
    const int f = kAlpha - e - 1;
7
9074
    const int k = (f * 78913) / (1 << 18) + (f > 0);
7
9075
7
9076
    const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
7
9077
    assert(index >= 0);
7
9078
    assert(index < kCachedPowersSize);
7
9079
    static_cast<void>(kCachedPowersSize); // Fix warning.
7
9080
7
9081
    const cached_power cached = kCachedPowers[index];
7
9082
    assert(kAlpha <= cached.e + e + 64);
7
9083
    assert(kGamma >= cached.e + e + 64);
7
9084
7
9085
    return cached;
7
9086
}
9087
9088
/*!
9089
For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
9090
For n == 0, returns 1 and sets pow10 := 1.
9091
*/
9092
inline int find_largest_pow10(const uint32_t n, uint32_t& pow10)
7
9093
{
7
9094
    // LCOV_EXCL_START
7
9095
    if (n >= 1000000000)
0
9096
    {
0
9097
        pow10 = 1000000000;
0
9098
        return 10;
0
9099
    }
7
9100
    // LCOV_EXCL_STOP
7
9101
    else if (n >= 100000000)
0
9102
    {
0
9103
        pow10 = 100000000;
0
9104
        return  9;
0
9105
    }
7
9106
    else if (n >= 10000000)
0
9107
    {
0
9108
        pow10 = 10000000;
0
9109
        return  8;
0
9110
    }
7
9111
    else if (n >= 1000000)
0
9112
    {
0
9113
        pow10 = 1000000;
0
9114
        return  7;
0
9115
    }
7
9116
    else if (n >= 100000)
6
9117
    {
6
9118
        pow10 = 100000;
6
9119
        return  6;
6
9120
    }
1
9121
    else if (n >= 10000)
1
9122
    {
1
9123
        pow10 = 10000;
1
9124
        return  5;
1
9125
    }
0
9126
    else if (n >= 1000)
0
9127
    {
0
9128
        pow10 = 1000;
0
9129
        return  4;
0
9130
    }
0
9131
    else if (n >= 100)
0
9132
    {
0
9133
        pow10 = 100;
0
9134
        return  3;
0
9135
    }
0
9136
    else if (n >= 10)
0
9137
    {
0
9138
        pow10 = 10;
0
9139
        return  2;
0
9140
    }
0
9141
    else
0
9142
    {
0
9143
        pow10 = 1;
0
9144
        return 1;
0
9145
    }
7
9146
}
9147
9148
inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta,
9149
                         uint64_t rest, uint64_t ten_k)
7
9150
{
7
9151
    assert(len >= 1);
7
9152
    assert(dist <= delta);
7
9153
    assert(rest <= delta);
7
9154
    assert(ten_k > 0);
7
9155
7
9156
    //               <--------------------------- delta ---->
7
9157
    //                                  <---- dist --------->
7
9158
    // --------------[------------------+-------------------]--------------
7
9159
    //               M-                 w                   M+
7
9160
    //
7
9161
    //                                  ten_k
7
9162
    //                                <------>
7
9163
    //                                       <---- rest ---->
7
9164
    // --------------[------------------+----+--------------]--------------
7
9165
    //                                  w    V
7
9166
    //                                       = buf * 10^k
7
9167
    //
7
9168
    // ten_k represents a unit-in-the-last-place in the decimal representation
7
9169
    // stored in buf.
7
9170
    // Decrement buf by ten_k while this takes buf closer to w.
7
9171
7
9172
    // The tests are written in this order to avoid overflow in unsigned
7
9173
    // integer arithmetic.
7
9174
7
9175
    while (rest < dist
4
9176
            and delta - rest >= ten_k
0
9177
            and (rest + ten_k < dist or dist - rest > rest + ten_k - dist))
0
9178
    {
0
9179
        assert(buf[len - 1] != '0');
0
9180
        buf[len - 1]--;
0
9181
        rest += ten_k;
0
9182
    }
7
9183
}
9184
9185
/*!
9186
Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
9187
M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
9188
*/
9189
inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
9190
                             diyfp M_minus, diyfp w, diyfp M_plus)
7
9191
{
7
9192
    static_assert(kAlpha >= -60, "internal error");
7
9193
    static_assert(kGamma <= -32, "internal error");
7
9194
7
9195
    // Generates the digits (and the exponent) of a decimal floating-point
7
9196
    // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's
7
9197
    // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.
7
9198
    //
7
9199
    //               <--------------------------- delta ---->
7
9200
    //                                  <---- dist --------->
7
9201
    // --------------[------------------+-------------------]--------------
7
9202
    //               M-                 w                   M+
7
9203
    //
7
9204
    // Grisu2 generates the digits of M+ from left to right and stops as soon as
7
9205
    // V is in [M-,M+].
7
9206
7
9207
    assert(M_plus.e >= kAlpha);
7
9208
    assert(M_plus.e <= kGamma);
7
9209
7
9210
    uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
7
9211
    uint64_t dist  = diyfp::sub(M_plus, w      ).f; // (significand of (M+ - w ), implicit exponent is e)
7
9212
7
9213
    // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
7
9214
    //
7
9215
    //      M+ = f * 2^e
7
9216
    //         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e
7
9217
    //         = ((p1        ) * 2^-e + (p2        )) * 2^e
7
9218
    //         = p1 + p2 * 2^e
7
9219
7
9220
    const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e);
7
9221
7
9222
    uint32_t p1 = static_cast<uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
7
9223
    uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e
7
9224
7
9225
    // 1)
7
9226
    //
7
9227
    // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
7
9228
7
9229
    assert(p1 > 0);
7
9230
7
9231
    uint32_t pow10;
7
9232
    const int k = find_largest_pow10(p1, pow10);
7
9233
7
9234
    //      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
7
9235
    //
7
9236
    //      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))
7
9237
    //         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))
7
9238
    //
7
9239
    //      M+ = p1                                             + p2 * 2^e
7
9240
    //         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e
7
9241
    //         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e
7
9242
    //         = d[k-1] * 10^(k-1) + (                         rest) * 2^e
7
9243
    //
7
9244
    // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)
7
9245
    //
7
9246
    //      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]
7
9247
    //
7
9248
    // but stop as soon as
7
9249
    //
7
9250
    //      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e
7
9251
7
9252
    int n = k;
41
9253
    while (n > 0)
37
9254
    {
37
9255
        // Invariants:
37
9256
        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)
37
9257
        //      pow10 = 10^(n-1) <= p1 < 10^n
37
9258
        //
37
9259
        const uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)
37
9260
        const uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)
37
9261
        //
37
9262
        //      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
37
9263
        //         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
37
9264
        //
37
9265
        assert(d <= 9);
37
9266
        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
37
9267
        //
37
9268
        //      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
37
9269
        //
37
9270
        p1 = r;
37
9271
        n--;
37
9272
        //
37
9273
        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)
37
9274
        //      pow10 = 10^n
37
9275
        //
37
9276
37
9277
        // Now check if enough digits have been generated.
37
9278
        // Compute
37
9279
        //
37
9280
        //      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e
37
9281
        //
37
9282
        // Note:
37
9283
        // Since rest and delta share the same exponent e, it suffices to
37
9284
        // compare the significands.
37
9285
        const uint64_t rest = (uint64_t{p1} << -one.e) + p2;
37
9286
        if (rest <= delta)
3
9287
        {
3
9288
            // V = buffer * 10^n, with M- <= V <= M+.
3
9289
3
9290
            decimal_exponent += n;
3
9291
3
9292
            // We may now just stop. But instead look if the buffer could be
3
9293
            // decremented to bring V closer to w.
3
9294
            //
3
9295
            // pow10 = 10^n is now 1 ulp in the decimal representation V.
3
9296
            // The rounding procedure works with diyfp's with an implicit
3
9297
            // exponent of e.
3
9298
            //
3
9299
            //      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
3
9300
            //
3
9301
            const uint64_t ten_n = uint64_t{pow10} << -one.e;
3
9302
            grisu2_round(buffer, length, dist, delta, rest, ten_n);
3
9303
3
9304
            return;
3
9305
        }
37
9306
34
9307
        pow10 /= 10;
34
9308
        //
34
9309
        //      pow10 = 10^(n-1) <= p1 < 10^n
34
9310
        // Invariants restored.
34
9311
    }
7
9312
7
9313
    // 2)
7
9314
    //
7
9315
    // The digits of the integral part have been generated:
7
9316
    //
7
9317
    //      M+ = d[k-1]...d[1]d[0] + p2 * 2^e
7
9318
    //         = buffer            + p2 * 2^e
7
9319
    //
7
9320
    // Now generate the digits of the fractional part p2 * 2^e.
7
9321
    //
7
9322
    // Note:
7
9323
    // No decimal point is generated: the exponent is adjusted instead.
7
9324
    //
7
9325
    // p2 actually represents the fraction
7
9326
    //
7
9327
    //      p2 * 2^e
7
9328
    //          = p2 / 2^-e
7
9329
    //          = d[-1] / 10^1 + d[-2] / 10^2 + ...
7
9330
    //
7
9331
    // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)
7
9332
    //
7
9333
    //      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m
7
9334
    //                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)
7
9335
    //
7
9336
    // using
7
9337
    //
7
9338
    //      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)
7
9339
    //                = (                   d) * 2^-e + (                   r)
7
9340
    //
7
9341
    // or
7
9342
    //      10^m * p2 * 2^e = d + r * 2^e
7
9343
    //
7
9344
    // i.e.
7
9345
    //
7
9346
    //      M+ = buffer + p2 * 2^e
7
9347
    //         = buffer + 10^-m * (d + r * 2^e)
7
9348
    //         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e
7
9349
    //
7
9350
    // and stop as soon as 10^-m * r * 2^e <= delta * 2^e
7
9351
4
9352
    assert(p2 > delta);
4
9353
4
9354
    int m = 0;
4
9355
    for (;;)
4
9356
    {
4
9357
        // Invariant:
4
9358
        //      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e
4
9359
        //         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e
4
9360
        //         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e
4
9361
        //         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
4
9362
        //
4
9363
        assert(p2 <= UINT64_MAX / 10);
4
9364
        p2 *= 10;
4
9365
        const uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e
4
9366
        const uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
4
9367
        //
4
9368
        //      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
4
9369
        //         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
4
9370
        //         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
4
9371
        //
4
9372
        assert(d <= 9);
4
9373
        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
4
9374
        //
4
9375
        //      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
4
9376
        //
4
9377
        p2 = r;
4
9378
        m++;
4
9379
        //
4
9380
        //      M+ = buffer * 10^-m + 10^-m * p2 * 2^e
4
9381
        // Invariant restored.
4
9382
4
9383
        // Check if enough digits have been generated.
4
9384
        //
4
9385
        //      10^-m * p2 * 2^e <= delta * 2^e
4
9386
        //              p2 * 2^e <= 10^m * delta * 2^e
4
9387
        //                    p2 <= 10^m * delta
4
9388
        delta *= 10;
4
9389
        dist  *= 10;
4
9390
        if (p2 <= delta)
4
9391
        {
4
9392
            break;
4
9393
        }
4
9394
    }
4
9395
4
9396
    // V = buffer * 10^-m, with M- <= V <= M+.
4
9397
4
9398
    decimal_exponent -= m;
4
9399
4
9400
    // 1 ulp in the decimal representation is now 10^-m.
4
9401
    // Since delta and dist are now scaled by 10^m, we need to do the
4
9402
    // same with ulp in order to keep the units in sync.
4
9403
    //
4
9404
    //      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
4
9405
    //
4
9406
    const uint64_t ten_m = one.f;
4
9407
    grisu2_round(buffer, length, dist, delta, p2, ten_m);
4
9408
4
9409
    // By construction this algorithm generates the shortest possible decimal
4
9410
    // number (Loitsch, Theorem 6.2) which rounds back to w.
4
9411
    // For an input number of precision p, at least
4
9412
    //
4
9413
    //      N = 1 + ceil(p * log_10(2))
4
9414
    //
4
9415
    // decimal digits are sufficient to identify all binary floating-point
4
9416
    // numbers (Matula, "In-and-Out conversions").
4
9417
    // This implies that the algorithm does not produce more than N decimal
4
9418
    // digits.
4
9419
    //
4
9420
    //      N = 17 for p = 53 (IEEE double precision)
4
9421
    //      N = 9  for p = 24 (IEEE single precision)
4
9422
}
9423
9424
/*!
9425
v = buf * 10^decimal_exponent
9426
len is the length of the buffer (number of decimal digits)
9427
The buffer must be large enough, i.e. >= max_digits10.
9428
*/
9429
inline void grisu2(char* buf, int& len, int& decimal_exponent,
9430
                   diyfp m_minus, diyfp v, diyfp m_plus)
7
9431
{
7
9432
    assert(m_plus.e == m_minus.e);
7
9433
    assert(m_plus.e == v.e);
7
9434
7
9435
    //  --------(-----------------------+-----------------------)--------    (A)
7
9436
    //          m-                      v                       m+
7
9437
    //
7
9438
    //  --------------------(-----------+-----------------------)--------    (B)
7
9439
    //                      m-          v                       m+
7
9440
    //
7
9441
    // First scale v (and m- and m+) such that the exponent is in the range
7
9442
    // [alpha, gamma].
7
9443
7
9444
    const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);
7
9445
7
9446
    const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k
7
9447
7
9448
    // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]
7
9449
    const diyfp w       = diyfp::mul(v,       c_minus_k);
7
9450
    const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);
7
9451
    const diyfp w_plus  = diyfp::mul(m_plus,  c_minus_k);
7
9452
7
9453
    //  ----(---+---)---------------(---+---)---------------(---+---)----
7
9454
    //          w-                      w                       w+
7
9455
    //          = c*m-                  = c*v                   = c*m+
7
9456
    //
7
9457
    // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and
7
9458
    // w+ are now off by a small amount.
7
9459
    // In fact:
7
9460
    //
7
9461
    //      w - v * 10^k < 1 ulp
7
9462
    //
7
9463
    // To account for this inaccuracy, add resp. subtract 1 ulp.
7
9464
    //
7
9465
    //  --------+---[---------------(---+---)---------------]---+--------
7
9466
    //          w-  M-                  w                   M+  w+
7
9467
    //
7
9468
    // Now any number in [M-, M+] (bounds included) will round to w when input,
7
9469
    // regardless of how the input rounding algorithm breaks ties.
7
9470
    //
7
9471
    // And digit_gen generates the shortest possible such number in [M-, M+].
7
9472
    // Note that this does not mean that Grisu2 always generates the shortest
7
9473
    // possible number in the interval (m-, m+).
7
9474
    const diyfp M_minus(w_minus.f + 1, w_minus.e);
7
9475
    const diyfp M_plus (w_plus.f  - 1, w_plus.e );
7
9476
7
9477
    decimal_exponent = -cached.k; // = -(-k) = k
7
9478
7
9479
    grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
7
9480
}
9481
9482
/*!
9483
v = buf * 10^decimal_exponent
9484
len is the length of the buffer (number of decimal digits)
9485
The buffer must be large enough, i.e. >= max_digits10.
9486
*/
9487
template <typename FloatType>
9488
void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
7
9489
{
7
9490
    static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
7
9491
                  "internal error: not enough precision");
7
9492
7
9493
    assert(std::isfinite(value));
7
9494
    assert(value > 0);
7
9495
7
9496
    // If the neighbors (and boundaries) of 'value' are always computed for double-precision
7
9497
    // numbers, all float's can be recovered using strtod (and strtof). However, the resulting
7
9498
    // decimal representations are not exactly "short".
7
9499
    //
7
9500
    // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)
7
9501
    // says "value is converted to a string as if by std::sprintf in the default ("C") locale"
7
9502
    // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'
7
9503
    // does.
7
9504
    // On the other hand, the documentation for 'std::to_chars' requires that "parsing the
7
9505
    // representation using the corresponding std::from_chars function recovers value exactly". That
7
9506
    // indicates that single precision floating-point numbers should be recovered using
7
9507
    // 'std::strtof'.
7
9508
    //
7
9509
    // NB: If the neighbors are computed for single-precision numbers, there is a single float
7
9510
    //     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
7
9511
    //     value is off by 1 ulp.
7
9512
#if 0
9513
    const boundaries w = compute_boundaries(static_cast<double>(value));
9514
#else
7
9515
    const boundaries w = compute_boundaries(value);
7
9516
#endif
7
9517
7
9518
    grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
7
9519
}
9520
9521
/*!
9522
@brief appends a decimal representation of e to buf
9523
@return a pointer to the element following the exponent.
9524
@pre -1000 < e < 1000
9525
*/
9526
inline char* append_exponent(char* buf, int e)
0
9527
{
0
9528
    assert(e > -1000);
0
9529
    assert(e <  1000);
0
9530
0
9531
    if (e < 0)
0
9532
    {
0
9533
        e = -e;
0
9534
        *buf++ = '-';
0
9535
    }
0
9536
    else
0
9537
    {
0
9538
        *buf++ = '+';
0
9539
    }
0
9540
0
9541
    uint32_t k = static_cast<uint32_t>(e);
0
9542
    if (k < 10)
0
9543
    {
0
9544
        // Always print at least two digits in the exponent.
0
9545
        // This is for compatibility with printf("%g").
0
9546
        *buf++ = '0';
0
9547
        *buf++ = static_cast<char>('0' + k);
0
9548
    }
0
9549
    else if (k < 100)
0
9550
    {
0
9551
        *buf++ = static_cast<char>('0' + k / 10);
0
9552
        k %= 10;
0
9553
        *buf++ = static_cast<char>('0' + k);
0
9554
    }
0
9555
    else
0
9556
    {
0
9557
        *buf++ = static_cast<char>('0' + k / 100);
0
9558
        k %= 100;
0
9559
        *buf++ = static_cast<char>('0' + k / 10);
0
9560
        k %= 10;
0
9561
        *buf++ = static_cast<char>('0' + k);
0
9562
    }
0
9563
0
9564
    return buf;
0
9565
}
9566
9567
/*!
9568
@brief prettify v = buf * 10^decimal_exponent
9569
9570
If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point
9571
notation. Otherwise it will be printed in exponential notation.
9572
9573
@pre min_exp < 0
9574
@pre max_exp > 0
9575
*/
9576
inline char* format_buffer(char* buf, int len, int decimal_exponent,
9577
                           int min_exp, int max_exp)
7
9578
{
7
9579
    assert(min_exp < 0);
7
9580
    assert(max_exp > 0);
7
9581
7
9582
    const int k = len;
7
9583
    const int n = len + decimal_exponent;
7
9584
7
9585
    // v = buf * 10^(n-k)
7
9586
    // k is the length of the buffer (number of decimal digits)
7
9587
    // n is the position of the decimal point relative to the start of the buffer.
7
9588
7
9589
    if (k <= n and n <= max_exp)
0
9590
    {
0
9591
        // digits[000]
0
9592
        // len <= max_exp + 2
0
9593
0
9594
        std::memset(buf + k, '0', static_cast<size_t>(n - k));
0
9595
        // Make it look like a floating-point number (#362, #378)
0
9596
        buf[n + 0] = '.';
0
9597
        buf[n + 1] = '0';
0
9598
        return buf + (n + 2);
0
9599
    }
7
9600
7
9601
    if (0 < n and n <= max_exp)
7
9602
    {
7
9603
        // dig.its
7
9604
        // len <= max_digits10 + 1
7
9605
7
9606
        assert(k > n);
7
9607
7
9608
        std::memmove(buf + (n + 1), buf + n, static_cast<size_t>(k - n));
7
9609
        buf[n] = '.';
7
9610
        return buf + (k + 1);
7
9611
    }
7
9612
0
9613
    if (min_exp < n and n <= 0)
0
9614
    {
0
9615
        // 0.[000]digits
0
9616
        // len <= 2 + (-min_exp - 1) + max_digits10
0
9617
0
9618
        std::memmove(buf + (2 + -n), buf, static_cast<size_t>(k));
0
9619
        buf[0] = '0';
0
9620
        buf[1] = '.';
0
9621
        std::memset(buf + 2, '0', static_cast<size_t>(-n));
0
9622
        return buf + (2 + (-n) + k);
0
9623
    }
0
9624
0
9625
    if (k == 1)
0
9626
    {
0
9627
        // dE+123
0
9628
        // len <= 1 + 5
0
9629
0
9630
        buf += 1;
0
9631
    }
0
9632
    else
0
9633
    {
0
9634
        // d.igitsE+123
0
9635
        // len <= max_digits10 + 1 + 5
0
9636
0
9637
        std::memmove(buf + 2, buf + 1, static_cast<size_t>(k - 1));
0
9638
        buf[1] = '.';
0
9639
        buf += 1 + k;
0
9640
    }
0
9641
0
9642
    *buf++ = 'e';
0
9643
    return append_exponent(buf, n - 1);
0
9644
}
9645
9646
} // namespace dtoa_impl
9647
9648
/*!
9649
@brief generates a decimal representation of the floating-point number value in [first, last).
9650
9651
The format of the resulting decimal representation is similar to printf's %g
9652
format. Returns an iterator pointing past-the-end of the decimal representation.
9653
9654
@note The input number must be finite, i.e. NaN's and Inf's are not supported.
9655
@note The buffer must be large enough.
9656
@note The result is NOT null-terminated.
9657
*/
9658
template <typename FloatType>
9659
char* to_chars(char* first, char* last, FloatType value)
7
9660
{
7
9661
    static_cast<void>(last); // maybe unused - fix warning
7
9662
    assert(std::isfinite(value));
7
9663
7
9664
    // Use signbit(value) instead of (value < 0) since signbit works for -0.
7
9665
    if (std::signbit(value))
0
9666
    {
0
9667
        value = -value;
0
9668
        *first++ = '-';
0
9669
    }
7
9670
7
9671
    if (value == 0) // +-0
0
9672
    {
0
9673
        *first++ = '0';
0
9674
        // Make it look like a floating-point number (#362, #378)
0
9675
        *first++ = '.';
0
9676
        *first++ = '0';
0
9677
        return first;
0
9678
    }
7
9679
7
9680
    assert(last - first >= std::numeric_limits<FloatType>::max_digits10);
7
9681
7
9682
    // Compute v = buffer * 10^decimal_exponent.
7
9683
    // The decimal digits are stored in the buffer, which needs to be interpreted
7
9684
    // as an unsigned decimal integer.
7
9685
    // len is the length of the buffer, i.e. the number of decimal digits.
7
9686
    int len = 0;
7
9687
    int decimal_exponent = 0;
7
9688
    dtoa_impl::grisu2(first, len, decimal_exponent, value);
7
9689
7
9690
    assert(len <= std::numeric_limits<FloatType>::max_digits10);
7
9691
7
9692
    // Format the buffer like printf("%.*g", prec, value)
7
9693
    constexpr int kMinExp = -4;
7
9694
    // Use digits10 here to increase compatibility with version 2.
7
9695
    constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
7
9696
7
9697
    assert(last - first >= kMaxExp + 2);
7
9698
    assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
7
9699
    assert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
7
9700
7
9701
    return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
7
9702
}
9703
9704
} // namespace detail
9705
} // namespace nlohmann
9706
9707
// #include <nlohmann/detail/macro_scope.hpp>
9708
9709
// #include <nlohmann/detail/meta/cpp_future.hpp>
9710
9711
// #include <nlohmann/detail/output/output_adapters.hpp>
9712
9713
// #include <nlohmann/detail/value_t.hpp>
9714
9715
9716
namespace nlohmann
9717
{
9718
namespace detail
9719
{
9720
///////////////////
9721
// serialization //
9722
///////////////////
9723
9724
template<typename BasicJsonType>
9725
class serializer
9726
{
9727
    using string_t = typename BasicJsonType::string_t;
9728
    using number_float_t = typename BasicJsonType::number_float_t;
9729
    using number_integer_t = typename BasicJsonType::number_integer_t;
9730
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
9731
    static constexpr uint8_t UTF8_ACCEPT = 0;
9732
    static constexpr uint8_t UTF8_REJECT = 1;
9733
9734
  public:
9735
    /*!
9736
    @param[in] s  output stream to serialize to
9737
    @param[in] ichar  indentation character to use
9738
    */
9739
    serializer(output_adapter_t<char> s, const char ichar)
9740
        : o(std::move(s)), loc(std::localeconv()),
9741
          thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)),
9742
          decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)),
9743
          indent_char(ichar), indent_string(512, indent_char)
54
9744
    {}
9745
9746
    // delete because of pointer members
9747
    serializer(const serializer&) = delete;
9748
    serializer& operator=(const serializer&) = delete;
9749
9750
    /*!
9751
    @brief internal implementation of the serialization function
9752
9753
    This function is called by the public member function dump and organizes
9754
    the serialization internally. The indentation level is propagated as
9755
    additional parameter. In case of arrays and objects, the function is
9756
    called recursively.
9757
9758
    - strings and object keys are escaped using `escape_string()`
9759
    - integer numbers are converted implicitly via `operator<<`
9760
    - floating-point numbers are converted to a string using `"%g"` format
9761
9762
    @param[in] val             value to serialize
9763
    @param[in] pretty_print    whether the output shall be pretty-printed
9764
    @param[in] indent_step     the indent level
9765
    @param[in] current_indent  the current indent level (only used internally)
9766
    */
9767
    void dump(const BasicJsonType& val, const bool pretty_print,
9768
              const bool ensure_ascii,
9769
              const unsigned int indent_step,
9770
              const unsigned int current_indent = 0)
1.12k
9771
    {
0
9772
        switch (val.m_type)
0
9773
        {
239
9774
            case value_t::object:
239
9775
            {
239
9776
                if (val.m_value.object->empty())
0
9777
                {
0
9778
                    o->write_characters("{}", 2);
0
9779
                    return;
0
9780
                }
239
9781
239
9782
                if (pretty_print)
159
9783
                {
159
9784
                    o->write_characters("{\n", 2);
159
9785
159
9786
                    // variable to hold indentation for recursive calls
159
9787
                    const auto new_indent = current_indent + indent_step;
159
9788
                    if (JSON_UNLIKELY(indent_string.size() < new_indent))
0
9789
                    {
0
9790
                        indent_string.resize(indent_string.size() * 2, ' ');
0
9791
                    }
159
9792
159
9793
                    // first n-1 elements
159
9794
                    auto i = val.m_value.object->cbegin();
801
9795
                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
642
9796
                    {
642
9797
                        o->write_characters(indent_string.c_str(), new_indent);
642
9798
                        o->write_character('\"');
642
9799
                        dump_escaped(i->first, ensure_ascii);
642
9800
                        o->write_characters("\": ", 3);
642
9801
                        dump(i->second, true, ensure_ascii, indent_step, new_indent);
642
9802
                        o->write_characters(",\n", 2);
642
9803
                    }
159
9804
159
9805
                    // last element
159
9806
                    assert(i != val.m_value.object->cend());
159
9807
                    assert(std::next(i) == val.m_value.object->cend());
159
9808
                    o->write_characters(indent_string.c_str(), new_indent);
159
9809
                    o->write_character('\"');
159
9810
                    dump_escaped(i->first, ensure_ascii);
159
9811
                    o->write_characters("\": ", 3);
159
9812
                    dump(i->second, true, ensure_ascii, indent_step, new_indent);
159
9813
159
9814
                    o->write_character('\n');
159
9815
                    o->write_characters(indent_string.c_str(), current_indent);
159
9816
                    o->write_character('}');
159
9817
                }
239
9818
                else
80
9819
                {
80
9820
                    o->write_character('{');
80
9821
80
9822
                    // first n-1 elements
80
9823
                    auto i = val.m_value.object->cbegin();
272
9824
                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
192
9825
                    {
192
9826
                        o->write_character('\"');
192
9827
                        dump_escaped(i->first, ensure_ascii);
192
9828
                        o->write_characters("\":", 2);
192
9829
                        dump(i->second, false, ensure_ascii, indent_step, current_indent);
192
9830
                        o->write_character(',');
192
9831
                    }
80
9832
80
9833
                    // last element
80
9834
                    assert(i != val.m_value.object->cend());
80
9835
                    assert(std::next(i) == val.m_value.object->cend());
80
9836
                    o->write_character('\"');
80
9837
                    dump_escaped(i->first, ensure_ascii);
80
9838
                    o->write_characters("\":", 2);
80
9839
                    dump(i->second, false, ensure_ascii, indent_step, current_indent);
80
9840
80
9841
                    o->write_character('}');
80
9842
                }
239
9843
239
9844
                return;
239
9845
            }
239
9846
1
9847
            case value_t::array:
1
9848
            {
1
9849
                if (val.m_value.array->empty())
0
9850
                {
0
9851
                    o->write_characters("[]", 2);
0
9852
                    return;
0
9853
                }
1
9854
1
9855
                if (pretty_print)
1
9856
                {
1
9857
                    o->write_characters("[\n", 2);
1
9858
1
9859
                    // variable to hold indentation for recursive calls
1
9860
                    const auto new_indent = current_indent + indent_step;
1
9861
                    if (JSON_UNLIKELY(indent_string.size() < new_indent))
0
9862
                    {
0
9863
                        indent_string.resize(indent_string.size() * 2, ' ');
0
9864
                    }
1
9865
1
9866
                    // first n-1 elements
1
9867
                    for (auto i = val.m_value.array->cbegin();
1
9868
                            i != val.m_value.array->cend() - 1; ++i)
0
9869
                    {
0
9870
                        o->write_characters(indent_string.c_str(), new_indent);
0
9871
                        dump(*i, true, ensure_ascii, indent_step, new_indent);
0
9872
                        o->write_characters(",\n", 2);
0
9873
                    }
1
9874
1
9875
                    // last element
1
9876
                    assert(not val.m_value.array->empty());
1
9877
                    o->write_characters(indent_string.c_str(), new_indent);
1
9878
                    dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
1
9879
1
9880
                    o->write_character('\n');
1
9881
                    o->write_characters(indent_string.c_str(), current_indent);
1
9882
                    o->write_character(']');
1
9883
                }
1
9884
                else
0
9885
                {
0
9886
                    o->write_character('[');
0
9887
0
9888
                    // first n-1 elements
0
9889
                    for (auto i = val.m_value.array->cbegin();
0
9890
                            i != val.m_value.array->cend() - 1; ++i)
0
9891
                    {
0
9892
                        dump(*i, false, ensure_ascii, indent_step, current_indent);
0
9893
                        o->write_character(',');
0
9894
                    }
0
9895
0
9896
                    // last element
0
9897
                    assert(not val.m_value.array->empty());
0
9898
                    dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
0
9899
0
9900
                    o->write_character(']');
0
9901
                }
1
9902
1
9903
                return;
1
9904
            }
1
9905
756
9906
            case value_t::string:
756
9907
            {
756
9908
                o->write_character('\"');
756
9909
                dump_escaped(*val.m_value.string, ensure_ascii);
756
9910
                o->write_character('\"');
756
9911
                return;
1
9912
            }
1
9913
2
9914
            case value_t::boolean:
2
9915
            {
2
9916
                if (val.m_value.boolean)
2
9917
                {
2
9918
                    o->write_characters("true", 4);
2
9919
                }
2
9920
                else
0
9921
                {
0
9922
                    o->write_characters("false", 5);
0
9923
                }
2
9924
                return;
1
9925
            }
1
9926
2
9927
            case value_t::number_integer:
2
9928
            {
2
9929
                dump_integer(val.m_value.number_integer);
2
9930
                return;
1
9931
            }
1
9932
107
9933
            case value_t::number_unsigned:
107
9934
            {
107
9935
                dump_integer(val.m_value.number_unsigned);
107
9936
                return;
1
9937
            }
1
9938
7
9939
            case value_t::number_float:
7
9940
            {
7
9941
                dump_float(val.m_value.number_float);
7
9942
                return;
1
9943
            }
1
9944
0
9945
            case value_t::discarded:
0
9946
            {
0
9947
                o->write_characters("<discarded>", 11);
0
9948
                return;
1
9949
            }
1
9950
14
9951
            case value_t::null:
14
9952
            {
14
9953
                o->write_characters("null", 4);
14
9954
                return;
1
9955
            }
0
9956
        }
1.12k
9957
    }
9958
9959
  private:
9960
    /*!
9961
    @brief dump escaped string
9962
9963
    Escape a string by replacing certain special characters by a sequence of an
9964
    escape character (backslash) and another character and other control
9965
    characters by a sequence of "\u" followed by a four-digit hex
9966
    representation. The escaped string is written to output stream @a o.
9967
9968
    @param[in] s  the string to escape
9969
    @param[in] ensure_ascii  whether to escape non-ASCII characters with
9970
                             \uXXXX sequences
9971
9972
    @complexity Linear in the length of string @a s.
9973
    */
9974
    void dump_escaped(const string_t& s, const bool ensure_ascii)
1.82k
9975
    {
1.82k
9976
        uint32_t codepoint;
1.82k
9977
        uint8_t state = UTF8_ACCEPT;
1.82k
9978
        std::size_t bytes = 0;  // number of bytes written to string_buffer
1.82k
9979
12.0k
9980
        for (std::size_t i = 0; i < s.size(); ++i)
10.2k
9981
        {
10.2k
9982
            const auto byte = static_cast<uint8_t>(s[i]);
10.2k
9983
10.2k
9984
            switch (decode(state, codepoint, byte))
10.2k
9985
            {
10.2k
9986
                case UTF8_ACCEPT:  // decode found a new code point
10.2k
9987
                {
10.2k
9988
                    switch (codepoint)
10.2k
9989
                    {
0
9990
                        case 0x08: // backspace
0
9991
                        {
0
9992
                            string_buffer[bytes++] = '\\';
0
9993
                            string_buffer[bytes++] = 'b';
0
9994
                            break;
0
9995
                        }
0
9996
0
9997
                        case 0x09: // horizontal tab
0
9998
                        {
0
9999
                            string_buffer[bytes++] = '\\';
0
10000
                            string_buffer[bytes++] = 't';
0
10001
                            break;
0
10002
                        }
0
10003
0
10004
                        case 0x0A: // newline
0
10005
                        {
0
10006
                            string_buffer[bytes++] = '\\';
0
10007
                            string_buffer[bytes++] = 'n';
0
10008
                            break;
0
10009
                        }
0
10010
0
10011
                        case 0x0C: // formfeed
0
10012
                        {
0
10013
                            string_buffer[bytes++] = '\\';
0
10014
                            string_buffer[bytes++] = 'f';
0
10015
                            break;
0
10016
                        }
0
10017
0
10018
                        case 0x0D: // carriage return
0
10019
                        {
0
10020
                            string_buffer[bytes++] = '\\';
0
10021
                            string_buffer[bytes++] = 'r';
0
10022
                            break;
0
10023
                        }
0
10024
0
10025
                        case 0x22: // quotation mark
0
10026
                        {
0
10027
                            string_buffer[bytes++] = '\\';
0
10028
                            string_buffer[bytes++] = '\"';
0
10029
                            break;
0
10030
                        }
0
10031
0
10032
                        case 0x5C: // reverse solidus
0
10033
                        {
0
10034
                            string_buffer[bytes++] = '\\';
0
10035
                            string_buffer[bytes++] = '\\';
0
10036
                            break;
0
10037
                        }
0
10038
10.2k
10039
                        default:
10.2k
10040
                        {
10.2k
10041
                            // escape control characters (0x00..0x1F) or, if
10.2k
10042
                            // ensure_ascii parameter is used, non-ASCII characters
10.2k
10043
                            if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F)))
0
10044
                            {
0
10045
                                if (codepoint <= 0xFFFF)
0
10046
                                {
0
10047
                                    std::snprintf(string_buffer.data() + bytes, 7, "\\u%04x",
0
10048
                                                  static_cast<uint16_t>(codepoint));
0
10049
                                    bytes += 6;
0
10050
                                }
0
10051
                                else
0
10052
                                {
0
10053
                                    std::snprintf(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
0
10054
                                                  static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)),
0
10055
                                                  static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF)));
0
10056
                                    bytes += 12;
0
10057
                                }
0
10058
                            }
10.2k
10059
                            else
10.2k
10060
                            {
10.2k
10061
                                // copy byte to buffer (all previous bytes
10.2k
10062
                                // been copied have in default case above)
10.2k
10063
                                string_buffer[bytes++] = s[i];
10.2k
10064
                            }
10.2k
10065
                            break;
0
10066
                        }
10.2k
10067
                    }
10.2k
10068
10.2k
10069
                    // write buffer and reset index; there must be 13 bytes
10.2k
10070
                    // left, as this is the maximal number of bytes to be
10.2k
10071
                    // written ("\uxxxx\uxxxx\0") for one code point
10.2k
10072
                    if (string_buffer.size() - bytes < 13)
0
10073
                    {
0
10074
                        o->write_characters(string_buffer.data(), bytes);
0
10075
                        bytes = 0;
0
10076
                    }
10.2k
10077
                    break;
10.2k
10078
                }
10.2k
10079
0
10080
                case UTF8_REJECT:  // decode found invalid UTF-8 byte
0
10081
                {
0
10082
                    std::string sn(3, '\0');
0
10083
                    snprintf(&sn[0], sn.size(), "%.2X", byte);
0
10084
                    JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn));
10.2k
10085
                }
10.2k
10086
0
10087
                default:  // decode found yet incomplete multi-byte code point
0
10088
                {
0
10089
                    if (not ensure_ascii)
0
10090
                    {
0
10091
                        // code point will not be escaped - copy byte to buffer
0
10092
                        string_buffer[bytes++] = s[i];
0
10093
                    }
0
10094
                    break;
10.2k
10095
                }
10.2k
10096
            }
10.2k
10097
        }
1.82k
10098
1.82k
10099
        if (JSON_LIKELY(state == UTF8_ACCEPT))
1.82k
10100
        {
1.82k
10101
            // write buffer
1.82k
10102
            if (bytes > 0)
1.82k
10103
            {
1.82k
10104
                o->write_characters(string_buffer.data(), bytes);
1.82k
10105
            }
1.82k
10106
        }
1.82k
10107
        else
0
10108
        {
0
10109
            // we finish reading, but do not accept: string was incomplete
0
10110
            std::string sn(3, '\0');
0
10111
            snprintf(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back()));
0
10112
            JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
0
10113
        }
1.82k
10114
    }
10115
10116
    /*!
10117
    @brief dump an integer
10118
10119
    Dump a given integer to output stream @a o. Works internally with
10120
    @a number_buffer.
10121
10122
    @param[in] x  integer number (signed or unsigned) to dump
10123
    @tparam NumberType either @a number_integer_t or @a number_unsigned_t
10124
    */
10125
    template<typename NumberType, detail::enable_if_t<
10126
                 std::is_same<NumberType, number_unsigned_t>::value or
10127
                 std::is_same<NumberType, number_integer_t>::value,
10128
                 int> = 0>
10129
    void dump_integer(NumberType x)
109
10130
    {
109
10131
        // special case for "0"
109
10132
        if (x == 0)
7
10133
        {
7
10134
            o->write_character('0');
7
10135
            return;
7
10136
        }
109
10137
102
10138
        const bool is_negative = (x <= 0) and (x != 0);  // see issue #755
102
10139
        std::size_t i = 0;
102
10140
305
10141
        while (x != 0)
203
10142
        {
203
10143
            // spare 1 byte for '\0'
203
10144
            assert(i < number_buffer.size() - 1);
203
10145
203
10146
            const auto digit = std::labs(static_cast<long>(x % 10));
203
10147
            number_buffer[i++] = static_cast<char>('0' + digit);
203
10148
            x /= 10;
203
10149
        }
102
10150
102
10151
        if (is_negative)
1
10152
        {
1
10153
            // make sure there is capacity for the '-'
1
10154
            assert(i < number_buffer.size() - 2);
1
10155
            number_buffer[i++] = '-';
1
10156
        }
102
10157
102
10158
        std::reverse(number_buffer.begin(), number_buffer.begin() + i);
102
10159
        o->write_characters(number_buffer.data(), i);
102
10160
    }
_ZN8nlohmann6detail10serializerINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12dump_integerImLi0EEEvT_
107
10130
    {
107
10131
        // special case for "0"
107
10132
        if (x == 0)
7
10133
        {
7
10134
            o->write_character('0');
7
10135
            return;
7
10136
        }
107
10137
100
10138
        const bool is_negative = (x <= 0) and (x != 0);  // see issue #755
100
10139
        std::size_t i = 0;
100
10140
296
10141
        while (x != 0)
196
10142
        {
196
10143
            // spare 1 byte for '\0'
196
10144
            assert(i < number_buffer.size() - 1);
196
10145
196
10146
            const auto digit = std::labs(static_cast<long>(x % 10));
196
10147
            number_buffer[i++] = static_cast<char>('0' + digit);
196
10148
            x /= 10;
196
10149
        }
100
10150
100
10151
        if (is_negative)
0
10152
        {
0
10153
            // make sure there is capacity for the '-'
0
10154
            assert(i < number_buffer.size() - 2);
0
10155
            number_buffer[i++] = '-';
0
10156
        }
100
10157
100
10158
        std::reverse(number_buffer.begin(), number_buffer.begin() + i);
100
10159
        o->write_characters(number_buffer.data(), i);
100
10160
    }
_ZN8nlohmann6detail10serializerINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12dump_integerIlLi0EEEvT_
2
10130
    {
2
10131
        // special case for "0"
2
10132
        if (x == 0)
0
10133
        {
0
10134
            o->write_character('0');
0
10135
            return;
0
10136
        }
2
10137
2
10138
        const bool is_negative = (x <= 0) and (x != 0);  // see issue #755
2
10139
        std::size_t i = 0;
2
10140
9
10141
        while (x != 0)
7
10142
        {
7
10143
            // spare 1 byte for '\0'
7
10144
            assert(i < number_buffer.size() - 1);
7
10145
7
10146
            const auto digit = std::labs(static_cast<long>(x % 10));
7
10147
            number_buffer[i++] = static_cast<char>('0' + digit);
7
10148
            x /= 10;
7
10149
        }
2
10150
2
10151
        if (is_negative)
1
10152
        {
1
10153
            // make sure there is capacity for the '-'
1
10154
            assert(i < number_buffer.size() - 2);
1
10155
            number_buffer[i++] = '-';
1
10156
        }
2
10157
2
10158
        std::reverse(number_buffer.begin(), number_buffer.begin() + i);
2
10159
        o->write_characters(number_buffer.data(), i);
2
10160
    }
10161
10162
    /*!
10163
    @brief dump a floating-point number
10164
10165
    Dump a given floating-point number to output stream @a o. Works internally
10166
    with @a number_buffer.
10167
10168
    @param[in] x  floating-point number to dump
10169
    */
10170
    void dump_float(number_float_t x)
7
10171
    {
7
10172
        // NaN / inf
7
10173
        if (not std::isfinite(x))
0
10174
        {
0
10175
            o->write_characters("null", 4);
0
10176
            return;
0
10177
        }
7
10178
7
10179
        // If number_float_t is an IEEE-754 single or double precision number,
7
10180
        // use the Grisu2 algorithm to produce short numbers which are
7
10181
        // guaranteed to round-trip, using strtof and strtod, resp.
7
10182
        //
7
10183
        // NB: The test below works if <long double> == <double>.
7
10184
        static constexpr bool is_ieee_single_or_double
0
10185
            = (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or
0
10186
              (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024);
7
10187
7
10188
        dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
7
10189
    }
10190
10191
    void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
7
10192
    {
7
10193
        char* begin = number_buffer.data();
7
10194
        char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
7
10195
7
10196
        o->write_characters(begin, static_cast<size_t>(end - begin));
7
10197
    }
10198
10199
    void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
10200
    {
10201
        // get number of digits for a float -> text -> float round-trip
10202
        static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
10203
10204
        // the actual conversion
10205
        std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
10206
10207
        // negative value indicates an error
10208
        assert(len > 0);
10209
        // check if buffer was large enough
10210
        assert(static_cast<std::size_t>(len) < number_buffer.size());
10211
10212
        // erase thousands separator
10213
        if (thousands_sep != '\0')
10214
        {
10215
            const auto end = std::remove(number_buffer.begin(),
10216
                                         number_buffer.begin() + len, thousands_sep);
10217
            std::fill(end, number_buffer.end(), '\0');
10218
            assert((end - number_buffer.begin()) <= len);
10219
            len = (end - number_buffer.begin());
10220
        }
10221
10222
        // convert decimal point to '.'
10223
        if (decimal_point != '\0' and decimal_point != '.')
10224
        {
10225
            const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
10226
            if (dec_pos != number_buffer.end())
10227
            {
10228
                *dec_pos = '.';
10229
            }
10230
        }
10231
10232
        o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
10233
10234
        // determine if need to append ".0"
10235
        const bool value_is_int_like =
10236
            std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
10237
                         [](char c)
10238
        {
10239
            return (c == '.' or c == 'e');
10240
        });
10241
10242
        if (value_is_int_like)
10243
        {
10244
            o->write_characters(".0", 2);
10245
        }
10246
    }
10247
10248
    /*!
10249
    @brief check whether a string is UTF-8 encoded
10250
10251
    The function checks each byte of a string whether it is UTF-8 encoded. The
10252
    result of the check is stored in the @a state parameter. The function must
10253
    be called initially with state 0 (accept). State 1 means the string must
10254
    be rejected, because the current byte is not allowed. If the string is
10255
    completely processed, but the state is non-zero, the string ended
10256
    prematurely; that is, the last byte indicated more bytes should have
10257
    followed.
10258
10259
    @param[in,out] state  the state of the decoding
10260
    @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)
10261
    @param[in] byte       next byte to decode
10262
    @return               new state
10263
10264
    @note The function has been edited: a std::array is used.
10265
10266
    @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
10267
    @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
10268
    */
10269
    static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept
10.2k
10270
    {
10.2k
10271
        static const std::array<uint8_t, 400> utf8d =
10.2k
10272
        {
10.2k
10273
            {
10.2k
10274
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
10.2k
10275
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
10.2k
10276
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
10.2k
10277
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
10.2k
10278
                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
10.2k
10279
                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
10.2k
10280
                8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
10.2k
10281
                0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
10.2k
10282
                0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
10.2k
10283
                0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
10.2k
10284
                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
10.2k
10285
                1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
10.2k
10286
                1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
10.2k
10287
                1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
10.2k
10288
            }
10.2k
10289
        };
10.2k
10290
10.2k
10291
        const uint8_t type = utf8d[byte];
10.2k
10292
10.2k
10293
        codep = (state != UTF8_ACCEPT)
0
10294
                ? (byte & 0x3fu) | (codep << 6)
10.2k
10295
                : static_cast<uint32_t>(0xff >> type) & (byte);
10.2k
10296
10.2k
10297
        state = utf8d[256u + state * 16u + type];
10.2k
10298
        return state;
10.2k
10299
    }
10300
10301
  private:
10302
    /// the output of the serializer
10303
    output_adapter_t<char> o = nullptr;
10304
10305
    /// a (hopefully) large enough character buffer
10306
    std::array<char, 64> number_buffer{{}};
10307
10308
    /// the locale
10309
    const std::lconv* loc = nullptr;
10310
    /// the locale's thousand separator character
10311
    const char thousands_sep = '\0';
10312
    /// the locale's decimal point character
10313
    const char decimal_point = '\0';
10314
10315
    /// string buffer
10316
    std::array<char, 512> string_buffer{{}};
10317
10318
    /// the indentation character
10319
    const char indent_char;
10320
    /// the indentation string
10321
    string_t indent_string;
10322
};
10323
}
10324
}
10325
10326
// #include <nlohmann/detail/json_ref.hpp>
10327
10328
10329
#include <initializer_list>
10330
#include <utility>
10331
10332
namespace nlohmann
10333
{
10334
namespace detail
10335
{
10336
template<typename BasicJsonType>
10337
class json_ref
10338
{
10339
  public:
10340
    using value_type = BasicJsonType;
10341
10342
    json_ref(value_type&& value)
10343
        : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true)
10344
    {}
10345
10346
    json_ref(const value_type& value)
10347
        : value_ref(const_cast<value_type*>(&value)), is_rvalue(false)
10348
    {}
10349
10350
    json_ref(std::initializer_list<json_ref> init)
10351
        : owned_value(init), value_ref(&owned_value), is_rvalue(true)
10352
    {}
10353
10354
    template<class... Args>
10355
    json_ref(Args&& ... args)
10356
        : owned_value(std::forward<Args>(args)...), value_ref(&owned_value), is_rvalue(true)
10357
    {}
10358
10359
    // class should be movable only
10360
    json_ref(json_ref&&) = default;
10361
    json_ref(const json_ref&) = delete;
10362
    json_ref& operator=(const json_ref&) = delete;
10363
10364
    value_type moved_or_copied() const
10365
    {
10366
        if (is_rvalue)
10367
        {
10368
            return std::move(*value_ref);
10369
        }
10370
        return *value_ref;
10371
    }
10372
10373
    value_type const& operator*() const
10374
    {
10375
        return *static_cast<value_type const*>(value_ref);
10376
    }
10377
10378
    value_type const* operator->() const
10379
    {
10380
        return static_cast<value_type const*>(value_ref);
10381
    }
10382
10383
  private:
10384
    mutable value_type owned_value = nullptr;
10385
    value_type* value_ref = nullptr;
10386
    const bool is_rvalue;
10387
};
10388
}
10389
}
10390
10391
// #include <nlohmann/detail/json_pointer.hpp>
10392
10393
10394
#include <cassert> // assert
10395
#include <numeric> // accumulate
10396
#include <string> // string
10397
#include <vector> // vector
10398
10399
// #include <nlohmann/detail/macro_scope.hpp>
10400
10401
// #include <nlohmann/detail/exceptions.hpp>
10402
10403
// #include <nlohmann/detail/value_t.hpp>
10404
10405
10406
namespace nlohmann
10407
{
10408
template<typename BasicJsonType>
10409
class json_pointer
10410
{
10411
    // allow basic_json to access private members
10412
    NLOHMANN_BASIC_JSON_TPL_DECLARATION
10413
    friend class basic_json;
10414
10415
  public:
10416
    /*!
10417
    @brief create JSON pointer
10418
10419
    Create a JSON pointer according to the syntax described in
10420
    [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
10421
10422
    @param[in] s  string representing the JSON pointer; if omitted, the empty
10423
                  string is assumed which references the whole JSON value
10424
10425
    @throw parse_error.107 if the given JSON pointer @a s is nonempty and does
10426
                           not begin with a slash (`/`); see example below
10427
10428
    @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is
10429
    not followed by `0` (representing `~`) or `1` (representing `/`); see
10430
    example below
10431
10432
    @liveexample{The example shows the construction several valid JSON pointers
10433
    as well as the exceptional behavior.,json_pointer}
10434
10435
    @since version 2.0.0
10436
    */
10437
    explicit json_pointer(const std::string& s = "")
10438
        : reference_tokens(split(s))
10439
    {}
10440
10441
    /*!
10442
    @brief return a string representation of the JSON pointer
10443
10444
    @invariant For each JSON pointer `ptr`, it holds:
10445
    @code {.cpp}
10446
    ptr == json_pointer(ptr.to_string());
10447
    @endcode
10448
10449
    @return a string representation of the JSON pointer
10450
10451
    @liveexample{The example shows the result of `to_string`.,
10452
    json_pointer__to_string}
10453
10454
    @since version 2.0.0
10455
    */
10456
    std::string to_string() const noexcept
10457
    {
10458
        return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
10459
                               std::string{},
10460
                               [](const std::string & a, const std::string & b)
10461
        {
10462
            return a + "/" + escape(b);
10463
        });
10464
    }
10465
10466
    /// @copydoc to_string()
10467
    operator std::string() const
10468
    {
10469
        return to_string();
10470
    }
10471
10472
    /*!
10473
    @param[in] s  reference token to be converted into an array index
10474
10475
    @return integer representation of @a s
10476
10477
    @throw out_of_range.404 if string @a s could not be converted to an integer
10478
    */
10479
    static int array_index(const std::string& s)
10480
    {
10481
        std::size_t processed_chars = 0;
10482
        const int res = std::stoi(s, &processed_chars);
10483
10484
        // check if the string was completely read
10485
        if (JSON_UNLIKELY(processed_chars != s.size()))
10486
        {
10487
            JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'"));
10488
        }
10489
10490
        return res;
10491
    }
10492
10493
  private:
10494
    /*!
10495
    @brief remove and return last reference pointer
10496
    @throw out_of_range.405 if JSON pointer has no parent
10497
    */
10498
    std::string pop_back()
10499
    {
10500
        if (JSON_UNLIKELY(is_root()))
10501
        {
10502
            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
10503
        }
10504
10505
        auto last = reference_tokens.back();
10506
        reference_tokens.pop_back();
10507
        return last;
10508
    }
10509
10510
    /// return whether pointer points to the root document
10511
    bool is_root() const
10512
    {
10513
        return reference_tokens.empty();
10514
    }
10515
10516
    json_pointer top() const
10517
    {
10518
        if (JSON_UNLIKELY(is_root()))
10519
        {
10520
            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
10521
        }
10522
10523
        json_pointer result = *this;
10524
        result.reference_tokens = {reference_tokens[0]};
10525
        return result;
10526
    }
10527
10528
    /*!
10529
    @brief create and return a reference to the pointed to value
10530
10531
    @complexity Linear in the number of reference tokens.
10532
10533
    @throw parse_error.109 if array index is not a number
10534
    @throw type_error.313 if value cannot be unflattened
10535
    */
10536
    BasicJsonType& get_and_create(BasicJsonType& j) const
10537
    {
10538
        using size_type = typename BasicJsonType::size_type;
10539
        auto result = &j;
10540
10541
        // in case no reference tokens exist, return a reference to the JSON value
10542
        // j which will be overwritten by a primitive value
10543
        for (const auto& reference_token : reference_tokens)
10544
        {
10545
            switch (result->m_type)
10546
            {
10547
                case detail::value_t::null:
10548
                {
10549
                    if (reference_token == "0")
10550
                    {
10551
                        // start a new array if reference token is 0
10552
                        result = &result->operator[](0);
10553
                    }
10554
                    else
10555
                    {
10556
                        // start a new object otherwise
10557
                        result = &result->operator[](reference_token);
10558
                    }
10559
                    break;
10560
                }
10561
10562
                case detail::value_t::object:
10563
                {
10564
                    // create an entry in the object
10565
                    result = &result->operator[](reference_token);
10566
                    break;
10567
                }
10568
10569
                case detail::value_t::array:
10570
                {
10571
                    // create an entry in the array
10572
                    JSON_TRY
10573
                    {
10574
                        result = &result->operator[](static_cast<size_type>(array_index(reference_token)));
10575
                    }
10576
                    JSON_CATCH(std::invalid_argument&)
10577
                    {
10578
                        JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
10579
                    }
10580
                    break;
10581
                }
10582
10583
                /*
10584
                The following code is only reached if there exists a reference
10585
                token _and_ the current value is primitive. In this case, we have
10586
                an error situation, because primitive values may only occur as
10587
                single value; that is, with an empty list of reference tokens.
10588
                */
10589
                default:
10590
                    JSON_THROW(detail::type_error::create(313, "invalid value to unflatten"));
10591
            }
10592
        }
10593
10594
        return *result;
10595
    }
10596
10597
    /*!
10598
    @brief return a reference to the pointed to value
10599
10600
    @note This version does not throw if a value is not present, but tries to
10601
          create nested values instead. For instance, calling this function
10602
          with pointer `"/this/that"` on a null value is equivalent to calling
10603
          `operator[]("this").operator[]("that")` on that value, effectively
10604
          changing the null value to an object.
10605
10606
    @param[in] ptr  a JSON value
10607
10608
    @return reference to the JSON value pointed to by the JSON pointer
10609
10610
    @complexity Linear in the length of the JSON pointer.
10611
10612
    @throw parse_error.106   if an array index begins with '0'
10613
    @throw parse_error.109   if an array index was not a number
10614
    @throw out_of_range.404  if the JSON pointer can not be resolved
10615
    */
10616
    BasicJsonType& get_unchecked(BasicJsonType* ptr) const
10617
    {
10618
        using size_type = typename BasicJsonType::size_type;
10619
        for (const auto& reference_token : reference_tokens)
10620
        {
10621
            // convert null values to arrays or objects before continuing
10622
            if (ptr->m_type == detail::value_t::null)
10623
            {
10624
                // check if reference token is a number
10625
                const bool nums =
10626
                    std::all_of(reference_token.begin(), reference_token.end(),
10627
                                [](const char x)
10628
                {
10629
                    return (x >= '0' and x <= '9');
10630
                });
10631
10632
                // change value to array for numbers or "-" or to object otherwise
10633
                *ptr = (nums or reference_token == "-")
10634
                       ? detail::value_t::array
10635
                       : detail::value_t::object;
10636
            }
10637
10638
            switch (ptr->m_type)
10639
            {
10640
                case detail::value_t::object:
10641
                {
10642
                    // use unchecked object access
10643
                    ptr = &ptr->operator[](reference_token);
10644
                    break;
10645
                }
10646
10647
                case detail::value_t::array:
10648
                {
10649
                    // error condition (cf. RFC 6901, Sect. 4)
10650
                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
10651
                    {
10652
                        JSON_THROW(detail::parse_error::create(106, 0,
10653
                                                               "array index '" + reference_token +
10654
                                                               "' must not begin with '0'"));
10655
                    }
10656
10657
                    if (reference_token == "-")
10658
                    {
10659
                        // explicitly treat "-" as index beyond the end
10660
                        ptr = &ptr->operator[](ptr->m_value.array->size());
10661
                    }
10662
                    else
10663
                    {
10664
                        // convert array index to number; unchecked access
10665
                        JSON_TRY
10666
                        {
10667
                            ptr = &ptr->operator[](
10668
                                static_cast<size_type>(array_index(reference_token)));
10669
                        }
10670
                        JSON_CATCH(std::invalid_argument&)
10671
                        {
10672
                            JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
10673
                        }
10674
                    }
10675
                    break;
10676
                }
10677
10678
                default:
10679
                    JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
10680
            }
10681
        }
10682
10683
        return *ptr;
10684
    }
10685
10686
    /*!
10687
    @throw parse_error.106   if an array index begins with '0'
10688
    @throw parse_error.109   if an array index was not a number
10689
    @throw out_of_range.402  if the array index '-' is used
10690
    @throw out_of_range.404  if the JSON pointer can not be resolved
10691
    */
10692
    BasicJsonType& get_checked(BasicJsonType* ptr) const
10693
    {
10694
        using size_type = typename BasicJsonType::size_type;
10695
        for (const auto& reference_token : reference_tokens)
10696
        {
10697
            switch (ptr->m_type)
10698
            {
10699
                case detail::value_t::object:
10700
                {
10701
                    // note: at performs range check
10702
                    ptr = &ptr->at(reference_token);
10703
                    break;
10704
                }
10705
10706
                case detail::value_t::array:
10707
                {
10708
                    if (JSON_UNLIKELY(reference_token == "-"))
10709
                    {
10710
                        // "-" always fails the range check
10711
                        JSON_THROW(detail::out_of_range::create(402,
10712
                                                                "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
10713
                                                                ") is out of range"));
10714
                    }
10715
10716
                    // error condition (cf. RFC 6901, Sect. 4)
10717
                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
10718
                    {
10719
                        JSON_THROW(detail::parse_error::create(106, 0,
10720
                                                               "array index '" + reference_token +
10721
                                                               "' must not begin with '0'"));
10722
                    }
10723
10724
                    // note: at performs range check
10725
                    JSON_TRY
10726
                    {
10727
                        ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
10728
                    }
10729
                    JSON_CATCH(std::invalid_argument&)
10730
                    {
10731
                        JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
10732
                    }
10733
                    break;
10734
                }
10735
10736
                default:
10737
                    JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
10738
            }
10739
        }
10740
10741
        return *ptr;
10742
    }
10743
10744
    /*!
10745
    @brief return a const reference to the pointed to value
10746
10747
    @param[in] ptr  a JSON value
10748
10749
    @return const reference to the JSON value pointed to by the JSON
10750
    pointer
10751
10752
    @throw parse_error.106   if an array index begins with '0'
10753
    @throw parse_error.109   if an array index was not a number
10754
    @throw out_of_range.402  if the array index '-' is used
10755
    @throw out_of_range.404  if the JSON pointer can not be resolved
10756
    */
10757
    const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
10758
    {
10759
        using size_type = typename BasicJsonType::size_type;
10760
        for (const auto& reference_token : reference_tokens)
10761
        {
10762
            switch (ptr->m_type)
10763
            {
10764
                case detail::value_t::object:
10765
                {
10766
                    // use unchecked object access
10767
                    ptr = &ptr->operator[](reference_token);
10768
                    break;
10769
                }
10770
10771
                case detail::value_t::array:
10772
                {
10773
                    if (JSON_UNLIKELY(reference_token == "-"))
10774
                    {
10775
                        // "-" cannot be used for const access
10776
                        JSON_THROW(detail::out_of_range::create(402,
10777
                                                                "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
10778
                                                                ") is out of range"));
10779
                    }
10780
10781
                    // error condition (cf. RFC 6901, Sect. 4)
10782
                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
10783
                    {
10784
                        JSON_THROW(detail::parse_error::create(106, 0,
10785
                                                               "array index '" + reference_token +
10786
                                                               "' must not begin with '0'"));
10787
                    }
10788
10789
                    // use unchecked array access
10790
                    JSON_TRY
10791
                    {
10792
                        ptr = &ptr->operator[](
10793
                            static_cast<size_type>(array_index(reference_token)));
10794
                    }
10795
                    JSON_CATCH(std::invalid_argument&)
10796
                    {
10797
                        JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
10798
                    }
10799
                    break;
10800
                }
10801
10802
                default:
10803
                    JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
10804
            }
10805
        }
10806
10807
        return *ptr;
10808
    }
10809
10810
    /*!
10811
    @throw parse_error.106   if an array index begins with '0'
10812
    @throw parse_error.109   if an array index was not a number
10813
    @throw out_of_range.402  if the array index '-' is used
10814
    @throw out_of_range.404  if the JSON pointer can not be resolved
10815
    */
10816
    const BasicJsonType& get_checked(const BasicJsonType* ptr) const
10817
    {
10818
        using size_type = typename BasicJsonType::size_type;
10819
        for (const auto& reference_token : reference_tokens)
10820
        {
10821
            switch (ptr->m_type)
10822
            {
10823
                case detail::value_t::object:
10824
                {
10825
                    // note: at performs range check
10826
                    ptr = &ptr->at(reference_token);
10827
                    break;
10828
                }
10829
10830
                case detail::value_t::array:
10831
                {
10832
                    if (JSON_UNLIKELY(reference_token == "-"))
10833
                    {
10834
                        // "-" always fails the range check
10835
                        JSON_THROW(detail::out_of_range::create(402,
10836
                                                                "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
10837
                                                                ") is out of range"));
10838
                    }
10839
10840
                    // error condition (cf. RFC 6901, Sect. 4)
10841
                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
10842
                    {
10843
                        JSON_THROW(detail::parse_error::create(106, 0,
10844
                                                               "array index '" + reference_token +
10845
                                                               "' must not begin with '0'"));
10846
                    }
10847
10848
                    // note: at performs range check
10849
                    JSON_TRY
10850
                    {
10851
                        ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
10852
                    }
10853
                    JSON_CATCH(std::invalid_argument&)
10854
                    {
10855
                        JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
10856
                    }
10857
                    break;
10858
                }
10859
10860
                default:
10861
                    JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
10862
            }
10863
        }
10864
10865
        return *ptr;
10866
    }
10867
10868
    /*!
10869
    @brief split the string input to reference tokens
10870
10871
    @note This function is only called by the json_pointer constructor.
10872
          All exceptions below are documented there.
10873
10874
    @throw parse_error.107  if the pointer is not empty or begins with '/'
10875
    @throw parse_error.108  if character '~' is not followed by '0' or '1'
10876
    */
10877
    static std::vector<std::string> split(const std::string& reference_string)
0
10878
    {
0
10879
        std::vector<std::string> result;
0
10880
0
10881
        // special case: empty reference string -> no reference tokens
0
10882
        if (reference_string.empty())
0
10883
        {
0
10884
            return result;
0
10885
        }
0
10886
0
10887
        // check if nonempty reference string begins with slash
0
10888
        if (JSON_UNLIKELY(reference_string[0] != '/'))
0
10889
        {
0
10890
            JSON_THROW(detail::parse_error::create(107, 1,
0
10891
                                                   "JSON pointer must be empty or begin with '/' - was: '" +
0
10892
                                                   reference_string + "'"));
0
10893
        }
0
10894
0
10895
        // extract the reference tokens:
0
10896
        // - slash: position of the last read slash (or end of string)
0
10897
        // - start: position after the previous slash
0
10898
        for (
0
10899
            // search for the first slash after the first character
0
10900
            std::size_t slash = reference_string.find_first_of('/', 1),
0
10901
            // set the beginning of the first reference token
0
10902
            start = 1;
0
10903
            // we can stop if start == string::npos+1 = 0
0
10904
            start != 0;
0
10905
            // set the beginning of the next reference token
0
10906
            // (will eventually be 0 if slash == std::string::npos)
0
10907
            start = slash + 1,
0
10908
            // find next slash
0
10909
            slash = reference_string.find_first_of('/', start))
0
10910
        {
0
10911
            // use the text between the beginning of the reference token
0
10912
            // (start) and the last slash (slash).
0
10913
            auto reference_token = reference_string.substr(start, slash - start);
0
10914
0
10915
            // check reference tokens are properly escaped
0
10916
            for (std::size_t pos = reference_token.find_first_of('~');
0
10917
                    pos != std::string::npos;
0
10918
                    pos = reference_token.find_first_of('~', pos + 1))
0
10919
            {
0
10920
                assert(reference_token[pos] == '~');
0
10921
0
10922
                // ~ must be followed by 0 or 1
0
10923
                if (JSON_UNLIKELY(pos == reference_token.size() - 1 or
0
10924
                                  (reference_token[pos + 1] != '0' and
0
10925
                                   reference_token[pos + 1] != '1')))
0
10926
                {
0
10927
                    JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'"));
0
10928
                }
0
10929
            }
0
10930
0
10931
            // finally, store the reference token
0
10932
            unescape(reference_token);
0
10933
            result.push_back(reference_token);
0
10934
        }
0
10935
0
10936
        return result;
0
10937
    }
10938
10939
    /*!
10940
    @brief replace all occurrences of a substring by another string
10941
10942
    @param[in,out] s  the string to manipulate; changed so that all
10943
                   occurrences of @a f are replaced with @a t
10944
    @param[in]     f  the substring to replace with @a t
10945
    @param[in]     t  the string to replace @a f
10946
10947
    @pre The search string @a f must not be empty. **This precondition is
10948
    enforced with an assertion.**
10949
10950
    @since version 2.0.0
10951
    */
10952
    static void replace_substring(std::string& s, const std::string& f,
10953
                                  const std::string& t)
0
10954
    {
0
10955
        assert(not f.empty());
0
10956
        for (auto pos = s.find(f);                // find first occurrence of f
0
10957
                pos != std::string::npos;         // make sure f was found
0
10958
                s.replace(pos, f.size(), t),      // replace with t, and
0
10959
                pos = s.find(f, pos + t.size()))  // find next occurrence of f
0
10960
        {}
0
10961
    }
10962
10963
    /// escape "~"" to "~0" and "/" to "~1"
10964
    static std::string escape(std::string s)
10965
    {
10966
        replace_substring(s, "~", "~0");
10967
        replace_substring(s, "/", "~1");
10968
        return s;
10969
    }
10970
10971
    /// unescape "~1" to tilde and "~0" to slash (order is important!)
10972
    static void unescape(std::string& s)
0
10973
    {
0
10974
        replace_substring(s, "~1", "/");
0
10975
        replace_substring(s, "~0", "~");
0
10976
    }
10977
10978
    /*!
10979
    @param[in] reference_string  the reference string to the current value
10980
    @param[in] value             the value to consider
10981
    @param[in,out] result        the result object to insert values to
10982
10983
    @note Empty objects or arrays are flattened to `null`.
10984
    */
10985
    static void flatten(const std::string& reference_string,
10986
                        const BasicJsonType& value,
10987
                        BasicJsonType& result)
10988
    {
10989
        switch (value.m_type)
10990
        {
10991
            case detail::value_t::array:
10992
            {
10993
                if (value.m_value.array->empty())
10994
                {
10995
                    // flatten empty array as null
10996
                    result[reference_string] = nullptr;
10997
                }
10998
                else
10999
                {
11000
                    // iterate array and use index as reference string
11001
                    for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
11002
                    {
11003
                        flatten(reference_string + "/" + std::to_string(i),
11004
                                value.m_value.array->operator[](i), result);
11005
                    }
11006
                }
11007
                break;
11008
            }
11009
11010
            case detail::value_t::object:
11011
            {
11012
                if (value.m_value.object->empty())
11013
                {
11014
                    // flatten empty object as null
11015
                    result[reference_string] = nullptr;
11016
                }
11017
                else
11018
                {
11019
                    // iterate object and use keys as reference string
11020
                    for (const auto& element : *value.m_value.object)
11021
                    {
11022
                        flatten(reference_string + "/" + escape(element.first), element.second, result);
11023
                    }
11024
                }
11025
                break;
11026
            }
11027
11028
            default:
11029
            {
11030
                // add primitive value with its reference string
11031
                result[reference_string] = value;
11032
                break;
11033
            }
11034
        }
11035
    }
11036
11037
    /*!
11038
    @param[in] value  flattened JSON
11039
11040
    @return unflattened JSON
11041
11042
    @throw parse_error.109 if array index is not a number
11043
    @throw type_error.314  if value is not an object
11044
    @throw type_error.315  if object values are not primitive
11045
    @throw type_error.313  if value cannot be unflattened
11046
    */
11047
    static BasicJsonType
11048
    unflatten(const BasicJsonType& value)
11049
    {
11050
        if (JSON_UNLIKELY(not value.is_object()))
11051
        {
11052
            JSON_THROW(detail::type_error::create(314, "only objects can be unflattened"));
11053
        }
11054
11055
        BasicJsonType result;
11056
11057
        // iterate the JSON object values
11058
        for (const auto& element : *value.m_value.object)
11059
        {
11060
            if (JSON_UNLIKELY(not element.second.is_primitive()))
11061
            {
11062
                JSON_THROW(detail::type_error::create(315, "values in object must be primitive"));
11063
            }
11064
11065
            // assign value to reference pointed to by JSON pointer; Note that if
11066
            // the JSON pointer is "" (i.e., points to the whole value), function
11067
            // get_and_create returns a reference to result itself. An assignment
11068
            // will then create a primitive value.
11069
            json_pointer(element.first).get_and_create(result) = element.second;
11070
        }
11071
11072
        return result;
11073
    }
11074
11075
    friend bool operator==(json_pointer const& lhs,
11076
                           json_pointer const& rhs) noexcept
11077
    {
11078
        return (lhs.reference_tokens == rhs.reference_tokens);
11079
    }
11080
11081
    friend bool operator!=(json_pointer const& lhs,
11082
                           json_pointer const& rhs) noexcept
11083
    {
11084
        return not (lhs == rhs);
11085
    }
11086
11087
    /// the reference tokens
11088
    std::vector<std::string> reference_tokens;
11089
};
11090
}
11091
11092
// #include <nlohmann/adl_serializer.hpp>
11093
11094
11095
#include <utility>
11096
11097
// #include <nlohmann/detail/conversions/from_json.hpp>
11098
11099
// #include <nlohmann/detail/conversions/to_json.hpp>
11100
11101
11102
namespace nlohmann
11103
{
11104
template<typename, typename>
11105
struct adl_serializer
11106
{
11107
    /*!
11108
    @brief convert a JSON value to any value type
11109
11110
    This function is usually called by the `get()` function of the
11111
    @ref basic_json class (either explicit or via conversion operators).
11112
11113
    @param[in] j         JSON value to read from
11114
    @param[in,out] val  value to write to
11115
    */
11116
    template<typename BasicJsonType, typename ValueType>
11117
    static auto from_json(BasicJsonType&& j, ValueType& val) noexcept(
11118
        noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) -> decltype(
11119
            ::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void()
11120
        )
3.56k
11121
    {
3.56k
11122
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
3.56k
11123
    }
_ZN8nlohmann14adl_serializerIbvE9from_jsonIRKNS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEbEEDTcmclL_ZNS_12_GLOBAL__N_19from_jsonEEclsr3stdE7forwardIT_Efp_Efp0_Ecvv_EEOSG_RT0_
2
11121
    {
2
11122
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
2
11123
    }
_ZN8nlohmann14adl_serializerINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEvE9from_jsonIRKNS_10basic_jsonISt3mapSt6vectorS6_blmdSaS0_EES6_EEDTcmclL_ZNS_12_GLOBAL__N_19from_jsonEEclsr3stdE7forwardIT_Efp_Efp0_Ecvv_EEOSG_RT0_
3.26k
11121
    {
3.26k
11122
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
3.26k
11123
    }
_ZN8nlohmann14adl_serializerIivE9from_jsonIRKNS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEiEEDTcmclL_ZNS_12_GLOBAL__N_19from_jsonEEclsr3stdE7forwardIT_Efp_Efp0_Ecvv_EEOSG_RT0_
152
11121
    {
152
11122
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
152
11123
    }
_ZN8nlohmann14adl_serializerIdvE9from_jsonIRKNS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEdEEDTcmclL_ZNS_12_GLOBAL__N_19from_jsonEEclsr3stdE7forwardIT_Efp_Efp0_Ecvv_EEOSG_RT0_
148
11121
    {
148
11122
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
148
11123
    }
11124
11125
    /*!
11126
    @brief convert any value type to a JSON value
11127
11128
    This function is usually called by the constructors of the @ref basic_json
11129
    class.
11130
11131
    @param[in,out] j  JSON value to write to
11132
    @param[in] val     value to read from
11133
    */
11134
    template <typename BasicJsonType, typename ValueType>
11135
    static auto to_json(BasicJsonType& j, ValueType&& val) noexcept(
11136
        noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))
11137
    -> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)),
11138
                void())
60.9k
11139
    {
60.9k
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
60.9k
11141
    }
_ZN8nlohmann14adl_serializerINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEvE7to_jsonINS_10basic_jsonISt3mapSt6vectorS6_blmdSaS0_EES6_EEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
144
11139
    {
144
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
144
11141
    }
_ZN8nlohmann14adl_serializerIA474_cvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERA474_KcEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSI_
58
11139
    {
58
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
58
11141
    }
_ZN8nlohmann14adl_serializerINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEvE7to_jsonINS_10basic_jsonISt3mapSt6vectorS6_blmdSaS0_EERS6_EEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
18.3k
11139
    {
18.3k
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
18.3k
11141
    }
_ZN8nlohmann14adl_serializerImvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERmEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
22.6k
11139
    {
22.6k
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
22.6k
11141
    }
_ZN8nlohmann14adl_serializerIlvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERlEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
2.69k
11139
    {
2.69k
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
2.69k
11141
    }
_ZN8nlohmann14adl_serializerIbvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERbEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
179
11139
    {
179
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
179
11141
    }
_ZN8nlohmann14adl_serializerIdvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERdEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
16.8k
11139
    {
16.8k
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
16.8k
11141
    }
_ZN8nlohmann14adl_serializerINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEvE7to_jsonINS_10basic_jsonISt3mapSt6vectorS6_blmdSaS0_EEKS6_EEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
16
11139
    {
16
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
16
11141
    }
_ZN8nlohmann14adl_serializerIivE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEiEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
1
11139
    {
1
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
1
11141
    }
_ZN8nlohmann14adl_serializerIA6_cvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERA6_KcEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSI_
1
11139
    {
1
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
1
11141
    }
_ZN8nlohmann14adl_serializerIdvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEdEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
1
11139
    {
1
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
1
11141
    }
_ZN8nlohmann14adl_serializerIbvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEbEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
1
11139
    {
1
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
1
11141
    }
_ZN8nlohmann14adl_serializerIPKcvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERKS2_EEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSI_
10
11139
    {
10
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
10
11141
    }
_ZN8nlohmann14adl_serializerIjvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERjEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
48
11139
    {
48
11140
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
48
11141
    }
11142
};
11143
}
11144
11145
11146
/*!
11147
@brief namespace for Niels Lohmann
11148
@see https://github.com/nlohmann
11149
@since version 1.0.0
11150
*/
11151
namespace nlohmann
11152
{
11153
11154
/*!
11155
@brief a class to store JSON values
11156
11157
@tparam ObjectType type for JSON objects (`std::map` by default; will be used
11158
in @ref object_t)
11159
@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used
11160
in @ref array_t)
11161
@tparam StringType type for JSON strings and object keys (`std::string` by
11162
default; will be used in @ref string_t)
11163
@tparam BooleanType type for JSON booleans (`bool` by default; will be used
11164
in @ref boolean_t)
11165
@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by
11166
default; will be used in @ref number_integer_t)
11167
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
11168
`uint64_t` by default; will be used in @ref number_unsigned_t)
11169
@tparam NumberFloatType type for JSON floating-point numbers (`double` by
11170
default; will be used in @ref number_float_t)
11171
@tparam AllocatorType type of the allocator to use (`std::allocator` by
11172
default)
11173
@tparam JSONSerializer the serializer to resolve internal calls to `to_json()`
11174
and `from_json()` (@ref adl_serializer by default)
11175
11176
@requirement The class satisfies the following concept requirements:
11177
- Basic
11178
 - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):
11179
   JSON values can be default constructed. The result will be a JSON null
11180
   value.
11181
 - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):
11182
   A JSON value can be constructed from an rvalue argument.
11183
 - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible):
11184
   A JSON value can be copy-constructed from an lvalue expression.
11185
 - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable):
11186
   A JSON value van be assigned from an rvalue argument.
11187
 - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable):
11188
   A JSON value can be copy-assigned from an lvalue expression.
11189
 - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible):
11190
   JSON values can be destructed.
11191
- Layout
11192
 - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType):
11193
   JSON values have
11194
   [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
11195
   All non-static data members are private and standard layout types, the
11196
   class has no virtual functions or (virtual) base classes.
11197
- Library-wide
11198
 - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable):
11199
   JSON values can be compared with `==`, see @ref
11200
   operator==(const_reference,const_reference).
11201
 - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):
11202
   JSON values can be compared with `<`, see @ref
11203
   operator<(const_reference,const_reference).
11204
 - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable):
11205
   Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
11206
   other compatible types, using unqualified function call @ref swap().
11207
 - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer):
11208
   JSON values can be compared against `std::nullptr_t` objects which are used
11209
   to model the `null` value.
11210
- Container
11211
 - [Container](https://en.cppreference.com/w/cpp/named_req/Container):
11212
   JSON values can be used like STL containers and provide iterator access.
11213
 - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer);
11214
   JSON values can be used like STL containers and provide reverse iterator
11215
   access.
11216
11217
@invariant The member variables @a m_value and @a m_type have the following
11218
relationship:
11219
- If `m_type == value_t::object`, then `m_value.object != nullptr`.
11220
- If `m_type == value_t::array`, then `m_value.array != nullptr`.
11221
- If `m_type == value_t::string`, then `m_value.string != nullptr`.
11222
The invariants are checked by member function assert_invariant().
11223
11224
@internal
11225
@note ObjectType trick from http://stackoverflow.com/a/9860911
11226
@endinternal
11227
11228
@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
11229
Format](http://rfc7159.net/rfc7159)
11230
11231
@since version 1.0.0
11232
11233
@nosubgrouping
11234
*/
11235
NLOHMANN_BASIC_JSON_TPL_DECLARATION
11236
class basic_json
11237
{
11238
  private:
11239
    template<detail::value_t> friend struct detail::external_constructor;
11240
    friend ::nlohmann::json_pointer<basic_json>;
11241
    friend ::nlohmann::detail::parser<basic_json>;
11242
    friend ::nlohmann::detail::serializer<basic_json>;
11243
    template<typename BasicJsonType>
11244
    friend class ::nlohmann::detail::iter_impl;
11245
    template<typename BasicJsonType, typename CharType>
11246
    friend class ::nlohmann::detail::binary_writer;
11247
    template<typename BasicJsonType, typename SAX>
11248
    friend class ::nlohmann::detail::binary_reader;
11249
    template<typename BasicJsonType>
11250
    friend class ::nlohmann::detail::json_sax_dom_parser;
11251
    template<typename BasicJsonType>
11252
    friend class ::nlohmann::detail::json_sax_dom_callback_parser;
11253
11254
    /// workaround type for MSVC
11255
    using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
11256
11257
    // convenience aliases for types residing in namespace detail;
11258
    using lexer = ::nlohmann::detail::lexer<basic_json>;
11259
    using parser = ::nlohmann::detail::parser<basic_json>;
11260
11261
    using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
11262
    template<typename BasicJsonType>
11263
    using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;
11264
    template<typename BasicJsonType>
11265
    using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;
11266
    template<typename Iterator>
11267
    using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;
11268
    template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;
11269
11270
    template<typename CharType>
11271
    using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
11272
11273
    using binary_reader = ::nlohmann::detail::binary_reader<basic_json>;
11274
    template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
11275
11276
    using serializer = ::nlohmann::detail::serializer<basic_json>;
11277
11278
  public:
11279
    using value_t = detail::value_t;
11280
    /// JSON Pointer, see @ref nlohmann::json_pointer
11281
    using json_pointer = ::nlohmann::json_pointer<basic_json>;
11282
    template<typename T, typename SFINAE>
11283
    using json_serializer = JSONSerializer<T, SFINAE>;
11284
    /// helper type for initializer lists of basic_json values
11285
    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
11286
11287
    using input_format_t = detail::input_format_t;
11288
    /// SAX interface type, see @ref nlohmann::json_sax
11289
    using json_sax_t = json_sax<basic_json>;
11290
11291
    ////////////////
11292
    // exceptions //
11293
    ////////////////
11294
11295
    /// @name exceptions
11296
    /// Classes to implement user-defined exceptions.
11297
    /// @{
11298
11299
    /// @copydoc detail::exception
11300
    using exception = detail::exception;
11301
    /// @copydoc detail::parse_error
11302
    using parse_error = detail::parse_error;
11303
    /// @copydoc detail::invalid_iterator
11304
    using invalid_iterator = detail::invalid_iterator;
11305
    /// @copydoc detail::type_error
11306
    using type_error = detail::type_error;
11307
    /// @copydoc detail::out_of_range
11308
    using out_of_range = detail::out_of_range;
11309
    /// @copydoc detail::other_error
11310
    using other_error = detail::other_error;
11311
11312
    /// @}
11313
11314
11315
    /////////////////////
11316
    // container types //
11317
    /////////////////////
11318
11319
    /// @name container types
11320
    /// The canonic container types to use @ref basic_json like any other STL
11321
    /// container.
11322
    /// @{
11323
11324
    /// the type of elements in a basic_json container
11325
    using value_type = basic_json;
11326
11327
    /// the type of an element reference
11328
    using reference = value_type&;
11329
    /// the type of an element const reference
11330
    using const_reference = const value_type&;
11331
11332
    /// a type to represent differences between iterators
11333
    using difference_type = std::ptrdiff_t;
11334
    /// a type to represent container sizes
11335
    using size_type = std::size_t;
11336
11337
    /// the allocator type
11338
    using allocator_type = AllocatorType<basic_json>;
11339
11340
    /// the type of an element pointer
11341
    using pointer = typename std::allocator_traits<allocator_type>::pointer;
11342
    /// the type of an element const pointer
11343
    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
11344
11345
    /// an iterator for a basic_json container
11346
    using iterator = iter_impl<basic_json>;
11347
    /// a const iterator for a basic_json container
11348
    using const_iterator = iter_impl<const basic_json>;
11349
    /// a reverse iterator for a basic_json container
11350
    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
11351
    /// a const reverse iterator for a basic_json container
11352
    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
11353
11354
    /// @}
11355
11356
11357
    /*!
11358
    @brief returns the allocator associated with the container
11359
    */
11360
    static allocator_type get_allocator()
11361
    {
11362
        return allocator_type();
11363
    }
11364
11365
    /*!
11366
    @brief returns version information on the library
11367
11368
    This function returns a JSON object with information about the library,
11369
    including the version number and information on the platform and compiler.
11370
11371
    @return JSON object holding version information
11372
    key         | description
11373
    ----------- | ---------------
11374
    `compiler`  | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).
11375
    `copyright` | The copyright line for the library as string.
11376
    `name`      | The name of the library as string.
11377
    `platform`  | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`.
11378
    `url`       | The URL of the project as string.
11379
    `version`   | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string).
11380
11381
    @liveexample{The following code shows an example output of the `meta()`
11382
    function.,meta}
11383
11384
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
11385
    changes to any JSON value.
11386
11387
    @complexity Constant.
11388
11389
    @since 2.1.0
11390
    */
11391
    static basic_json meta()
11392
    {
11393
        basic_json result;
11394
11395
        result["copyright"] = "(C) 2013-2017 Niels Lohmann";
11396
        result["name"] = "JSON for Modern C++";
11397
        result["url"] = "https://github.com/nlohmann/json";
11398
        result["version"]["string"] =
11399
            std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." +
11400
            std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." +
11401
            std::to_string(NLOHMANN_JSON_VERSION_PATCH);
11402
        result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
11403
        result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
11404
        result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
11405
11406
#ifdef _WIN32
11407
        result["platform"] = "win32";
11408
#elif defined __linux__
11409
        result["platform"] = "linux";
11410
#elif defined __APPLE__
11411
        result["platform"] = "apple";
11412
#elif defined __unix__
11413
        result["platform"] = "unix";
11414
#else
11415
        result["platform"] = "unknown";
11416
#endif
11417
11418
#if defined(__ICC) || defined(__INTEL_COMPILER)
11419
        result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
11420
#elif defined(__clang__)
11421
        result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
11422
#elif defined(__GNUC__) || defined(__GNUG__)
11423
        result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}};
11424
#elif defined(__HP_cc) || defined(__HP_aCC)
11425
        result["compiler"] = "hp"
11426
#elif defined(__IBMCPP__)
11427
        result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
11428
#elif defined(_MSC_VER)
11429
        result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
11430
#elif defined(__PGI)
11431
        result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
11432
#elif defined(__SUNPRO_CC)
11433
        result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
11434
#else
11435
        result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
11436
#endif
11437
11438
#ifdef __cplusplus
11439
        result["compiler"]["c++"] = std::to_string(__cplusplus);
11440
#else
11441
        result["compiler"]["c++"] = "unknown";
11442
#endif
11443
        return result;
11444
    }
11445
11446
11447
    ///////////////////////////
11448
    // JSON value data types //
11449
    ///////////////////////////
11450
11451
    /// @name JSON value data types
11452
    /// The data types to store a JSON value. These types are derived from
11453
    /// the template arguments passed to class @ref basic_json.
11454
    /// @{
11455
11456
#if defined(JSON_HAS_CPP_14)
11457
    // Use transparent comparator if possible, combined with perfect forwarding
11458
    // on find() and count() calls prevents unnecessary string construction.
11459
    using object_comparator_t = std::less<>;
11460
#else
11461
    using object_comparator_t = std::less<StringType>;
11462
#endif
11463
11464
    /*!
11465
    @brief a type for an object
11466
11467
    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
11468
    > An object is an unordered collection of zero or more name/value pairs,
11469
    > where a name is a string and a value is a string, number, boolean, null,
11470
    > object, or array.
11471
11472
    To store objects in C++, a type is defined by the template parameters
11473
    described below.
11474
11475
    @tparam ObjectType  the container to store objects (e.g., `std::map` or
11476
    `std::unordered_map`)
11477
    @tparam StringType the type of the keys or names (e.g., `std::string`).
11478
    The comparison function `std::less<StringType>` is used to order elements
11479
    inside the container.
11480
    @tparam AllocatorType the allocator to use for objects (e.g.,
11481
    `std::allocator`)
11482
11483
    #### Default type
11484
11485
    With the default values for @a ObjectType (`std::map`), @a StringType
11486
    (`std::string`), and @a AllocatorType (`std::allocator`), the default
11487
    value for @a object_t is:
11488
11489
    @code {.cpp}
11490
    std::map<
11491
      std::string, // key_type
11492
      basic_json, // value_type
11493
      std::less<std::string>, // key_compare
11494
      std::allocator<std::pair<const std::string, basic_json>> // allocator_type
11495
    >
11496
    @endcode
11497
11498
    #### Behavior
11499
11500
    The choice of @a object_t influences the behavior of the JSON class. With
11501
    the default type, objects have the following behavior:
11502
11503
    - When all names are unique, objects will be interoperable in the sense
11504
      that all software implementations receiving that object will agree on
11505
      the name-value mappings.
11506
    - When the names within an object are not unique, it is unspecified which
11507
      one of the values for a given key will be chosen. For instance,
11508
      `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or
11509
      `{"key": 2}`.
11510
    - Internally, name/value pairs are stored in lexicographical order of the
11511
      names. Objects will also be serialized (see @ref dump) in this order.
11512
      For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
11513
      and serialized as `{"a": 2, "b": 1}`.
11514
    - When comparing objects, the order of the name/value pairs is irrelevant.
11515
      This makes objects interoperable in the sense that they will not be
11516
      affected by these differences. For instance, `{"b": 1, "a": 2}` and
11517
      `{"a": 2, "b": 1}` will be treated as equal.
11518
11519
    #### Limits
11520
11521
    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
11522
    > An implementation may set limits on the maximum depth of nesting.
11523
11524
    In this class, the object's limit of nesting is not explicitly constrained.
11525
    However, a maximum depth of nesting may be introduced by the compiler or
11526
    runtime environment. A theoretical limit can be queried by calling the
11527
    @ref max_size function of a JSON object.
11528
11529
    #### Storage
11530
11531
    Objects are stored as pointers in a @ref basic_json type. That is, for any
11532
    access to object values, a pointer of type `object_t*` must be
11533
    dereferenced.
11534
11535
    @sa @ref array_t -- type for an array value
11536
11537
    @since version 1.0.0
11538
11539
    @note The order name/value pairs are added to the object is *not*
11540
    preserved by the library. Therefore, iterating an object may return
11541
    name/value pairs in a different order than they were originally stored. In
11542
    fact, keys will be traversed in alphabetical order as `std::map` with
11543
    `std::less` is used by default. Please note this behavior conforms to [RFC
11544
    7159](http://rfc7159.net/rfc7159), because any order implements the
11545
    specified "unordered" nature of JSON objects.
11546
    */
11547
    using object_t = ObjectType<StringType,
11548
          basic_json,
11549
          object_comparator_t,
11550
          AllocatorType<std::pair<const StringType,
11551
          basic_json>>>;
11552
11553
    /*!
11554
    @brief a type for an array
11555
11556
    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
11557
    > An array is an ordered sequence of zero or more values.
11558
11559
    To store objects in C++, a type is defined by the template parameters
11560
    explained below.
11561
11562
    @tparam ArrayType  container type to store arrays (e.g., `std::vector` or
11563
    `std::list`)
11564
    @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)
11565
11566
    #### Default type
11567
11568
    With the default values for @a ArrayType (`std::vector`) and @a
11569
    AllocatorType (`std::allocator`), the default value for @a array_t is:
11570
11571
    @code {.cpp}
11572
    std::vector<
11573
      basic_json, // value_type
11574
      std::allocator<basic_json> // allocator_type
11575
    >
11576
    @endcode
11577
11578
    #### Limits
11579
11580
    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
11581
    > An implementation may set limits on the maximum depth of nesting.
11582
11583
    In this class, the array's limit of nesting is not explicitly constrained.
11584
    However, a maximum depth of nesting may be introduced by the compiler or
11585
    runtime environment. A theoretical limit can be queried by calling the
11586
    @ref max_size function of a JSON array.
11587
11588
    #### Storage
11589
11590
    Arrays are stored as pointers in a @ref basic_json type. That is, for any
11591
    access to array values, a pointer of type `array_t*` must be dereferenced.
11592
11593
    @sa @ref object_t -- type for an object value
11594
11595
    @since version 1.0.0
11596
    */
11597
    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
11598
11599
    /*!
11600
    @brief a type for a string
11601
11602
    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
11603
    > A string is a sequence of zero or more Unicode characters.
11604
11605
    To store objects in C++, a type is defined by the template parameter
11606
    described below. Unicode values are split by the JSON class into
11607
    byte-sized characters during deserialization.
11608
11609
    @tparam StringType  the container to store strings (e.g., `std::string`).
11610
    Note this container is used for keys/names in objects, see @ref object_t.
11611
11612
    #### Default type
11613
11614
    With the default values for @a StringType (`std::string`), the default
11615
    value for @a string_t is:
11616
11617
    @code {.cpp}
11618
    std::string
11619
    @endcode
11620
11621
    #### Encoding
11622
11623
    Strings are stored in UTF-8 encoding. Therefore, functions like
11624
    `std::string::size()` or `std::string::length()` return the number of
11625
    bytes in the string rather than the number of characters or glyphs.
11626
11627
    #### String comparison
11628
11629
    [RFC 7159](http://rfc7159.net/rfc7159) states:
11630
    > Software implementations are typically required to test names of object
11631
    > members for equality. Implementations that transform the textual
11632
    > representation into sequences of Unicode code units and then perform the
11633
    > comparison numerically, code unit by code unit, are interoperable in the
11634
    > sense that implementations will agree in all cases on equality or
11635
    > inequality of two strings. For example, implementations that compare
11636
    > strings with escaped characters unconverted may incorrectly find that
11637
    > `"a\\b"` and `"a\u005Cb"` are not equal.
11638
11639
    This implementation is interoperable as it does compare strings code unit
11640
    by code unit.
11641
11642
    #### Storage
11643
11644
    String values are stored as pointers in a @ref basic_json type. That is,
11645
    for any access to string values, a pointer of type `string_t*` must be
11646
    dereferenced.
11647
11648
    @since version 1.0.0
11649
    */
11650
    using string_t = StringType;
11651
11652
    /*!
11653
    @brief a type for a boolean
11654
11655
    [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
11656
    type which differentiates the two literals `true` and `false`.
11657
11658
    To store objects in C++, a type is defined by the template parameter @a
11659
    BooleanType which chooses the type to use.
11660
11661
    #### Default type
11662
11663
    With the default values for @a BooleanType (`bool`), the default value for
11664
    @a boolean_t is:
11665
11666
    @code {.cpp}
11667
    bool
11668
    @endcode
11669
11670
    #### Storage
11671
11672
    Boolean values are stored directly inside a @ref basic_json type.
11673
11674
    @since version 1.0.0
11675
    */
11676
    using boolean_t = BooleanType;
11677
11678
    /*!
11679
    @brief a type for a number (integer)
11680
11681
    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
11682
    > The representation of numbers is similar to that used in most
11683
    > programming languages. A number is represented in base 10 using decimal
11684
    > digits. It contains an integer component that may be prefixed with an
11685
    > optional minus sign, which may be followed by a fraction part and/or an
11686
    > exponent part. Leading zeros are not allowed. (...) Numeric values that
11687
    > cannot be represented in the grammar below (such as Infinity and NaN)
11688
    > are not permitted.
11689
11690
    This description includes both integer and floating-point numbers.
11691
    However, C++ allows more precise storage if it is known whether the number
11692
    is a signed integer, an unsigned integer or a floating-point number.
11693
    Therefore, three different types, @ref number_integer_t, @ref
11694
    number_unsigned_t and @ref number_float_t are used.
11695
11696
    To store integer numbers in C++, a type is defined by the template
11697
    parameter @a NumberIntegerType which chooses the type to use.
11698
11699
    #### Default type
11700
11701
    With the default values for @a NumberIntegerType (`int64_t`), the default
11702
    value for @a number_integer_t is:
11703
11704
    @code {.cpp}
11705
    int64_t
11706
    @endcode
11707
11708
    #### Default behavior
11709
11710
    - The restrictions about leading zeros is not enforced in C++. Instead,
11711
      leading zeros in integer literals lead to an interpretation as octal
11712
      number. Internally, the value will be stored as decimal number. For
11713
      instance, the C++ integer literal `010` will be serialized to `8`.
11714
      During deserialization, leading zeros yield an error.
11715
    - Not-a-number (NaN) values will be serialized to `null`.
11716
11717
    #### Limits
11718
11719
    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
11720
    > An implementation may set limits on the range and precision of numbers.
11721
11722
    When the default type is used, the maximal integer number that can be
11723
    stored is `9223372036854775807` (INT64_MAX) and the minimal integer number
11724
    that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
11725
    that are out of range will yield over/underflow when used in a
11726
    constructor. During deserialization, too large or small integer numbers
11727
    will be automatically be stored as @ref number_unsigned_t or @ref
11728
    number_float_t.
11729
11730
    [RFC 7159](http://rfc7159.net/rfc7159) further states:
11731
    > Note that when such software is used, numbers that are integers and are
11732
    > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
11733
    > that implementations will agree exactly on their numeric values.
11734
11735
    As this range is a subrange of the exactly supported range [INT64_MIN,
11736
    INT64_MAX], this class's integer type is interoperable.
11737
11738
    #### Storage
11739
11740
    Integer number values are stored directly inside a @ref basic_json type.
11741
11742
    @sa @ref number_float_t -- type for number values (floating-point)
11743
11744
    @sa @ref number_unsigned_t -- type for number values (unsigned integer)
11745
11746
    @since version 1.0.0
11747
    */
11748
    using number_integer_t = NumberIntegerType;
11749
11750
    /*!
11751
    @brief a type for a number (unsigned)
11752
11753
    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
11754
    > The representation of numbers is similar to that used in most
11755
    > programming languages. A number is represented in base 10 using decimal
11756
    > digits. It contains an integer component that may be prefixed with an
11757
    > optional minus sign, which may be followed by a fraction part and/or an
11758
    > exponent part. Leading zeros are not allowed. (...) Numeric values that
11759
    > cannot be represented in the grammar below (such as Infinity and NaN)
11760
    > are not permitted.
11761
11762
    This description includes both integer and floating-point numbers.
11763
    However, C++ allows more precise storage if it is known whether the number
11764
    is a signed integer, an unsigned integer or a floating-point number.
11765
    Therefore, three different types, @ref number_integer_t, @ref
11766
    number_unsigned_t and @ref number_float_t are used.
11767
11768
    To store unsigned integer numbers in C++, a type is defined by the
11769
    template parameter @a NumberUnsignedType which chooses the type to use.
11770
11771
    #### Default type
11772
11773
    With the default values for @a NumberUnsignedType (`uint64_t`), the
11774
    default value for @a number_unsigned_t is:
11775
11776
    @code {.cpp}
11777
    uint64_t
11778
    @endcode
11779
11780
    #### Default behavior
11781
11782
    - The restrictions about leading zeros is not enforced in C++. Instead,
11783
      leading zeros in integer literals lead to an interpretation as octal
11784
      number. Internally, the value will be stored as decimal number. For
11785
      instance, the C++ integer literal `010` will be serialized to `8`.
11786
      During deserialization, leading zeros yield an error.
11787
    - Not-a-number (NaN) values will be serialized to `null`.
11788
11789
    #### Limits
11790
11791
    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
11792
    > An implementation may set limits on the range and precision of numbers.
11793
11794
    When the default type is used, the maximal integer number that can be
11795
    stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
11796
    number that can be stored is `0`. Integer numbers that are out of range
11797
    will yield over/underflow when used in a constructor. During
11798
    deserialization, too large or small integer numbers will be automatically
11799
    be stored as @ref number_integer_t or @ref number_float_t.
11800
11801
    [RFC 7159](http://rfc7159.net/rfc7159) further states:
11802
    > Note that when such software is used, numbers that are integers and are
11803
    > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
11804
    > that implementations will agree exactly on their numeric values.
11805
11806
    As this range is a subrange (when considered in conjunction with the
11807
    number_integer_t type) of the exactly supported range [0, UINT64_MAX],
11808
    this class's integer type is interoperable.
11809
11810
    #### Storage
11811
11812
    Integer number values are stored directly inside a @ref basic_json type.
11813
11814
    @sa @ref number_float_t -- type for number values (floating-point)
11815
    @sa @ref number_integer_t -- type for number values (integer)
11816
11817
    @since version 2.0.0
11818
    */
11819
    using number_unsigned_t = NumberUnsignedType;
11820
11821
    /*!
11822
    @brief a type for a number (floating-point)
11823
11824
    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
11825
    > The representation of numbers is similar to that used in most
11826
    > programming languages. A number is represented in base 10 using decimal
11827
    > digits. It contains an integer component that may be prefixed with an
11828
    > optional minus sign, which may be followed by a fraction part and/or an
11829
    > exponent part. Leading zeros are not allowed. (...) Numeric values that
11830
    > cannot be represented in the grammar below (such as Infinity and NaN)
11831
    > are not permitted.
11832
11833
    This description includes both integer and floating-point numbers.
11834
    However, C++ allows more precise storage if it is known whether the number
11835
    is a signed integer, an unsigned integer or a floating-point number.
11836
    Therefore, three different types, @ref number_integer_t, @ref
11837
    number_unsigned_t and @ref number_float_t are used.
11838
11839
    To store floating-point numbers in C++, a type is defined by the template
11840
    parameter @a NumberFloatType which chooses the type to use.
11841
11842
    #### Default type
11843
11844
    With the default values for @a NumberFloatType (`double`), the default
11845
    value for @a number_float_t is:
11846
11847
    @code {.cpp}
11848
    double
11849
    @endcode
11850
11851
    #### Default behavior
11852
11853
    - The restrictions about leading zeros is not enforced in C++. Instead,
11854
      leading zeros in floating-point literals will be ignored. Internally,
11855
      the value will be stored as decimal number. For instance, the C++
11856
      floating-point literal `01.2` will be serialized to `1.2`. During
11857
      deserialization, leading zeros yield an error.
11858
    - Not-a-number (NaN) values will be serialized to `null`.
11859
11860
    #### Limits
11861
11862
    [RFC 7159](http://rfc7159.net/rfc7159) states:
11863
    > This specification allows implementations to set limits on the range and
11864
    > precision of numbers accepted. Since software that implements IEEE
11865
    > 754-2008 binary64 (double precision) numbers is generally available and
11866
    > widely used, good interoperability can be achieved by implementations
11867
    > that expect no more precision or range than these provide, in the sense
11868
    > that implementations will approximate JSON numbers within the expected
11869
    > precision.
11870
11871
    This implementation does exactly follow this approach, as it uses double
11872
    precision floating-point numbers. Note values smaller than
11873
    `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`
11874
    will be stored as NaN internally and be serialized to `null`.
11875
11876
    #### Storage
11877
11878
    Floating-point number values are stored directly inside a @ref basic_json
11879
    type.
11880
11881
    @sa @ref number_integer_t -- type for number values (integer)
11882
11883
    @sa @ref number_unsigned_t -- type for number values (unsigned integer)
11884
11885
    @since version 1.0.0
11886
    */
11887
    using number_float_t = NumberFloatType;
11888
11889
    /// @}
11890
11891
  private:
11892
11893
    /// helper for exception-safe object creation
11894
    template<typename T, typename... Args>
11895
    static T* create(Args&& ... args)
47.2k
11896
    {
47.2k
11897
        AllocatorType<T> alloc;
47.2k
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
47.2k
11899
47.2k
11900
        auto deleter = [&](T * object)
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
_ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JS8_EEEPT_DpOT0_ENKUlPS8_E_clESC_
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
_ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS2_ISA_SaISA_EEJEEEPT_DpOT0_ENKUlPSD_E_clESE_
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
_ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA1_KcEEEPT_DpOT0_ENKUlPS8_E_clESF_
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
_ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS1_IS8_SA_St4lessIvESaISt4pairIKS8_SA_EEEJRKSI_EEEPT_DpOT0_ENKUlPSI_E_clESL_
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
_ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS2_ISA_SaISA_EEJRKSD_EEEPT_DpOT0_ENKUlPSD_E_clESG_
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
_ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRKS8_EEEPT_DpOT0_ENKUlPS8_E_clESE_
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
_ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA474_KcEEEPT_DpOT0_ENKUlPS8_E_clESF_
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
_ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA6_KcEEEPT_DpOT0_ENKUlPS8_E_clESF_
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
_ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS1_IS8_SA_St4lessIvESaISt4pairIKS8_SA_EEEJEEEPT_DpOT0_ENKUlPSI_E_clESJ_
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
_ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRKPKcEEEPT_DpOT0_ENKUlPS8_E_clESG_
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
47.2k
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
47.2k
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
47.2k
11906
        assert(object != nullptr);
47.2k
11907
        return object.release();
47.2k
11908
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS1_IS8_SA_St4lessIvESaISt4pairIKS8_SA_EEEJEEEPT_DpOT0_
15.0k
11896
    {
15.0k
11897
        AllocatorType<T> alloc;
15.0k
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
15.0k
11899
15.0k
11900
        auto deleter = [&](T * object)
15.0k
11901
        {
15.0k
11902
            AllocatorTraits::deallocate(alloc, object, 1);
15.0k
11903
        };
15.0k
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
15.0k
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
15.0k
11906
        assert(object != nullptr);
15.0k
11907
        return object.release();
15.0k
11908
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA6_KcEEEPT_DpOT0_
1
11896
    {
1
11897
        AllocatorType<T> alloc;
1
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
1
11899
1
11900
        auto deleter = [&](T * object)
1
11901
        {
1
11902
            AllocatorTraits::deallocate(alloc, object, 1);
1
11903
        };
1
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
1
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
1
11906
        assert(object != nullptr);
1
11907
        return object.release();
1
11908
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRKPKcEEEPT_DpOT0_
10
11896
    {
10
11897
        AllocatorType<T> alloc;
10
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
10
11899
10
11900
        auto deleter = [&](T * object)
10
11901
        {
10
11902
            AllocatorTraits::deallocate(alloc, object, 1);
10
11903
        };
10
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
10
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
10
11906
        assert(object != nullptr);
10
11907
        return object.release();
10
11908
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JS8_EEEPT_DpOT0_
144
11896
    {
144
11897
        AllocatorType<T> alloc;
144
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
144
11899
144
11900
        auto deleter = [&](T * object)
144
11901
        {
144
11902
            AllocatorTraits::deallocate(alloc, object, 1);
144
11903
        };
144
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
144
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
144
11906
        assert(object != nullptr);
144
11907
        return object.release();
144
11908
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA474_KcEEEPT_DpOT0_
58
11896
    {
58
11897
        AllocatorType<T> alloc;
58
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
58
11899
58
11900
        auto deleter = [&](T * object)
58
11901
        {
58
11902
            AllocatorTraits::deallocate(alloc, object, 1);
58
11903
        };
58
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
58
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
58
11906
        assert(object != nullptr);
58
11907
        return object.release();
58
11908
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRKS8_EEEPT_DpOT0_
28.5k
11896
    {
28.5k
11897
        AllocatorType<T> alloc;
28.5k
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
28.5k
11899
28.5k
11900
        auto deleter = [&](T * object)
28.5k
11901
        {
28.5k
11902
            AllocatorTraits::deallocate(alloc, object, 1);
28.5k
11903
        };
28.5k
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
28.5k
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
28.5k
11906
        assert(object != nullptr);
28.5k
11907
        return object.release();
28.5k
11908
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS2_ISA_SaISA_EEJRKSD_EEEPT_DpOT0_
24
11896
    {
24
11897
        AllocatorType<T> alloc;
24
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
24
11899
24
11900
        auto deleter = [&](T * object)
24
11901
        {
24
11902
            AllocatorTraits::deallocate(alloc, object, 1);
24
11903
        };
24
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
24
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
24
11906
        assert(object != nullptr);
24
11907
        return object.release();
24
11908
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS1_IS8_SA_St4lessIvESaISt4pairIKS8_SA_EEEJRKSI_EEEPT_DpOT0_
3.24k
11896
    {
3.24k
11897
        AllocatorType<T> alloc;
3.24k
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
3.24k
11899
3.24k
11900
        auto deleter = [&](T * object)
3.24k
11901
        {
3.24k
11902
            AllocatorTraits::deallocate(alloc, object, 1);
3.24k
11903
        };
3.24k
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
3.24k
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
3.24k
11906
        assert(object != nullptr);
3.24k
11907
        return object.release();
3.24k
11908
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA1_KcEEEPT_DpOT0_
0
11896
    {
0
11897
        AllocatorType<T> alloc;
0
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
0
11899
0
11900
        auto deleter = [&](T * object)
0
11901
        {
0
11902
            AllocatorTraits::deallocate(alloc, object, 1);
0
11903
        };
0
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
0
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
0
11906
        assert(object != nullptr);
0
11907
        return object.release();
0
11908
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS2_ISA_SaISA_EEJEEEPT_DpOT0_
178
11896
    {
178
11897
        AllocatorType<T> alloc;
178
11898
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
178
11899
178
11900
        auto deleter = [&](T * object)
178
11901
        {
178
11902
            AllocatorTraits::deallocate(alloc, object, 1);
178
11903
        };
178
11904
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
178
11905
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
178
11906
        assert(object != nullptr);
178
11907
        return object.release();
178
11908
    }
11909
11910
    ////////////////////////
11911
    // JSON value storage //
11912
    ////////////////////////
11913
11914
    /*!
11915
    @brief a JSON value
11916
11917
    The actual storage for a JSON value of the @ref basic_json class. This
11918
    union combines the different storage types for the JSON value types
11919
    defined in @ref value_t.
11920
11921
    JSON type | value_t type    | used type
11922
    --------- | --------------- | ------------------------
11923
    object    | object          | pointer to @ref object_t
11924
    array     | array           | pointer to @ref array_t
11925
    string    | string          | pointer to @ref string_t
11926
    boolean   | boolean         | @ref boolean_t
11927
    number    | number_integer  | @ref number_integer_t
11928
    number    | number_unsigned | @ref number_unsigned_t
11929
    number    | number_float    | @ref number_float_t
11930
    null      | null            | *no value is stored*
11931
11932
    @note Variable-length types (objects, arrays, and strings) are stored as
11933
    pointers. The size of the union should not exceed 64 bits if the default
11934
    value types are used.
11935
11936
    @since version 1.0.0
11937
    */
11938
    union json_value
11939
    {
11940
        /// object (stored with pointer to save storage)
11941
        object_t* object;
11942
        /// array (stored with pointer to save storage)
11943
        array_t* array;
11944
        /// string (stored with pointer to save storage)
11945
        string_t* string;
11946
        /// boolean
11947
        boolean_t boolean;
11948
        /// number (integer)
11949
        number_integer_t number_integer;
11950
        /// number (unsigned integer)
11951
        number_unsigned_t number_unsigned;
11952
        /// number (floating-point)
11953
        number_float_t number_float;
11954
11955
        /// default constructor (for null values)
11956
        json_value() = default;
11957
        /// constructor for booleans
192
11958
        json_value(boolean_t v) noexcept : boolean(v) {}
_ZN8nlohmann10basic_json10json_valueC2ET2_
0
11958
        json_value(boolean_t v) noexcept : boolean(v) {}
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE10json_valueC2Eb
192
11958
        json_value(boolean_t v) noexcept : boolean(v) {}
11959
        /// constructor for numbers (integer)
3.11k
11960
        json_value(number_integer_t v) noexcept : number_integer(v) {}
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE10json_valueC2El
3.11k
11960
        json_value(number_integer_t v) noexcept : number_integer(v) {}
_ZN8nlohmann10basic_json10json_valueC2ET3_
0
11960
        json_value(number_integer_t v) noexcept : number_integer(v) {}
11961
        /// constructor for numbers (unsigned)
26.2k
11962
        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE10json_valueC2Em
26.2k
11962
        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
_ZN8nlohmann10basic_json10json_valueC2ET4_
0
11962
        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
11963
        /// constructor for numbers (floating-point)
19.4k
11964
        json_value(number_float_t v) noexcept : number_float(v) {}
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE10json_valueC2Ed
19.4k
11964
        json_value(number_float_t v) noexcept : number_float(v) {}
_ZN8nlohmann10basic_json10json_valueC2ET5_
0
11964
        json_value(number_float_t v) noexcept : number_float(v) {}
11965
        /// constructor for empty values of a given type
11966
        json_value(value_t t)
88.9k
11967
        {
88.9k
11968
            switch (t)
88.9k
11969
            {
15.0k
11970
                case value_t::object:
15.0k
11971
                {
15.0k
11972
                    object = create<object_t>();
15.0k
11973
                    break;
15.0k
11974
                }
15.0k
11975
178
11976
                case value_t::array:
178
11977
                {
178
11978
                    array = create<array_t>();
178
11979
                    break;
15.0k
11980
                }
15.0k
11981
0
11982
                case value_t::string:
0
11983
                {
0
11984
                    string = create<string_t>("");
0
11985
                    break;
15.0k
11986
                }
15.0k
11987
0
11988
                case value_t::boolean:
0
11989
                {
0
11990
                    boolean = boolean_t(false);
0
11991
                    break;
15.0k
11992
                }
15.0k
11993
0
11994
                case value_t::number_integer:
0
11995
                {
0
11996
                    number_integer = number_integer_t(0);
0
11997
                    break;
15.0k
11998
                }
15.0k
11999
0
12000
                case value_t::number_unsigned:
0
12001
                {
0
12002
                    number_unsigned = number_unsigned_t(0);
0
12003
                    break;
15.0k
12004
                }
15.0k
12005
0
12006
                case value_t::number_float:
0
12007
                {
0
12008
                    number_float = number_float_t(0.0);
0
12009
                    break;
15.0k
12010
                }
15.0k
12011
73.7k
12012
                case value_t::null:
73.7k
12013
                {
73.7k
12014
                    object = nullptr;  // silence warning, see #821
73.7k
12015
                    break;
15.0k
12016
                }
15.0k
12017
0
12018
                default:
0
12019
                {
0
12020
                    object = nullptr;  // silence warning, see #821
0
12021
                    if (JSON_UNLIKELY(t == value_t::null))
0
12022
                    {
0
12023
                        JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.2.0")); // LCOV_EXCL_LINE
0
12024
                    }
0
12025
                    break;
0
12026
                }
88.9k
12027
            }
88.9k
12028
        }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE10json_valueC2ENS_6detail7value_tE
88.9k
11967
        {
88.9k
11968
            switch (t)
88.9k
11969
            {
15.0k
11970
                case value_t::object:
15.0k
11971
                {
15.0k
11972
                    object = create<object_t>();
15.0k
11973
                    break;
15.0k
11974
                }
15.0k
11975
178
11976
                case value_t::array:
178
11977
                {
178
11978
                    array = create<array_t>();
178
11979
                    break;
15.0k
11980
                }
15.0k
11981
0
11982
                case value_t::string:
0
11983
                {
0
11984
                    string = create<string_t>("");
0
11985
                    break;
15.0k
11986
                }
15.0k
11987
0
11988
                case value_t::boolean:
0
11989
                {
0
11990
                    boolean = boolean_t(false);
0
11991
                    break;
15.0k
11992
                }
15.0k
11993
0
11994
                case value_t::number_integer:
0
11995
                {
0
11996
                    number_integer = number_integer_t(0);
0
11997
                    break;
15.0k
11998
                }
15.0k
11999
0
12000
                case value_t::number_unsigned:
0
12001
                {
0
12002
                    number_unsigned = number_unsigned_t(0);
0
12003
                    break;
15.0k
12004
                }
15.0k
12005
0
12006
                case value_t::number_float:
0
12007
                {
0
12008
                    number_float = number_float_t(0.0);
0
12009
                    break;
15.0k
12010
                }
15.0k
12011
73.7k
12012
                case value_t::null:
73.7k
12013
                {
73.7k
12014
                    object = nullptr;  // silence warning, see #821
73.7k
12015
                    break;
15.0k
12016
                }
15.0k
12017
0
12018
                default:
0
12019
                {
0
12020
                    object = nullptr;  // silence warning, see #821
0
12021
                    if (JSON_UNLIKELY(t == value_t::null))
0
12022
                    {
0
12023
                        JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.2.0")); // LCOV_EXCL_LINE
0
12024
                    }
0
12025
                    break;
0
12026
                }
88.9k
12027
            }
88.9k
12028
        }
_ZN8nlohmann10basic_json10json_valueC2ENS_6detail7value_tE
0
11967
        {
0
11968
            switch (t)
0
11969
            {
0
11970
                case value_t::object:
0
11971
                {
0
11972
                    object = create<object_t>();
0
11973
                    break;
0
11974
                }
0
11975
0
11976
                case value_t::array:
0
11977
                {
0
11978
                    array = create<array_t>();
0
11979
                    break;
0
11980
                }
0
11981
0
11982
                case value_t::string:
0
11983
                {
0
11984
                    string = create<string_t>("");
0
11985
                    break;
0
11986
                }
0
11987
0
11988
                case value_t::boolean:
0
11989
                {
0
11990
                    boolean = boolean_t(false);
0
11991
                    break;
0
11992
                }
0
11993
0
11994
                case value_t::number_integer:
0
11995
                {
0
11996
                    number_integer = number_integer_t(0);
0
11997
                    break;
0
11998
                }
0
11999
0
12000
                case value_t::number_unsigned:
0
12001
                {
0
12002
                    number_unsigned = number_unsigned_t(0);
0
12003
                    break;
0
12004
                }
0
12005
0
12006
                case value_t::number_float:
0
12007
                {
0
12008
                    number_float = number_float_t(0.0);
0
12009
                    break;
0
12010
                }
0
12011
0
12012
                case value_t::null:
0
12013
                {
0
12014
                    object = nullptr;  // silence warning, see #821
0
12015
                    break;
0
12016
                }
0
12017
0
12018
                default:
0
12019
                {
0
12020
                    object = nullptr;  // silence warning, see #821
0
12021
                    if (JSON_UNLIKELY(t == value_t::null))
0
12022
                    {
0
12023
                        JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.2.0")); // LCOV_EXCL_LINE
0
12024
                    }
0
12025
                    break;
0
12026
                }
0
12027
            }
0
12028
        }
12029
12030
        /// constructor for strings
12031
        json_value(const string_t& value)
28.5k
12032
        {
28.5k
12033
            string = create<string_t>(value);
28.5k
12034
        }
_ZN8nlohmann10basic_json10json_valueC2ERKT1_
0
12032
        {
0
12033
            string = create<string_t>(value);
0
12034
        }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE10json_valueC2ERKS8_
28.5k
12032
        {
28.5k
12033
            string = create<string_t>(value);
28.5k
12034
        }
12035
12036
        /// constructor for rvalue strings
12037
        json_value(string_t&& value)
144
12038
        {
144
12039
            string = create<string_t>(std::move(value));
144
12040
        }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE10json_valueC2EOS8_
144
12038
        {
144
12039
            string = create<string_t>(std::move(value));
144
12040
        }
_ZN8nlohmann10basic_json10json_valueC2EOT1_
0
12038
        {
0
12039
            string = create<string_t>(std::move(value));
0
12040
        }
12041
12042
        /// constructor for objects
12043
        json_value(const object_t& value)
3.24k
12044
        {
3.24k
12045
            object = create<object_t>(value);
3.24k
12046
        }
_ZN8nlohmann10basic_json10json_valueC2ERKT_IT1_NS_10basic_jsonIS2_T0_S3_T2_T3_T4_T5_T6_T7_EEJSt4lessIvESA_ISt4pairIKS3_SD_EEEE
0
12044
        {
0
12045
            object = create<object_t>(value);
0
12046
        }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE10json_valueC2ERKS1_IS8_SA_St4lessIvESaISt4pairIKS8_SA_EEE
3.24k
12044
        {
3.24k
12045
            object = create<object_t>(value);
3.24k
12046
        }
12047
12048
        /// constructor for rvalue objects
12049
        json_value(object_t&& value)
0
12050
        {
0
12051
            object = create<object_t>(std::move(value));
0
12052
        }
12053
12054
        /// constructor for arrays
12055
        json_value(const array_t& value)
24
12056
        {
24
12057
            array = create<array_t>(value);
24
12058
        }
_ZN8nlohmann10basic_json10json_valueC2ERKT0_INS_10basic_jsonIT_S2_T1_T2_T3_T4_T5_T6_T7_EEJSA_ISD_EEE
0
12056
        {
0
12057
            array = create<array_t>(value);
0
12058
        }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE10json_valueC2ERKS2_ISA_SaISA_EE
24
12056
        {
24
12057
            array = create<array_t>(value);
24
12058
        }
12059
12060
        /// constructor for rvalue arrays
12061
        json_value(array_t&& value)
0
12062
        {
0
12063
            array = create<array_t>(std::move(value));
0
12064
        }
12065
12066
        void destroy(value_t t) noexcept
173k
12067
        {
173k
12068
            switch (t)
173k
12069
            {
18.3k
12070
                case value_t::object:
18.3k
12071
                {
18.3k
12072
                    AllocatorType<object_t> alloc;
18.3k
12073
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
18.3k
12074
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
18.3k
12075
                    break;
18.3k
12076
                }
18.3k
12077
202
12078
                case value_t::array:
202
12079
                {
202
12080
                    AllocatorType<array_t> alloc;
202
12081
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
202
12082
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
202
12083
                    break;
18.3k
12084
                }
18.3k
12085
28.7k
12086
                case value_t::string:
28.7k
12087
                {
28.7k
12088
                    AllocatorType<string_t> alloc;
28.7k
12089
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
28.7k
12090
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
28.7k
12091
                    break;
18.3k
12092
                }
18.3k
12093
126k
12094
                default:
126k
12095
                {
126k
12096
                    break;
18.3k
12097
                }
173k
12098
            }
173k
12099
        }
_ZN8nlohmann10basic_json10json_value7destroyENS_6detail7value_tE
0
12067
        {
0
12068
            switch (t)
0
12069
            {
0
12070
                case value_t::object:
0
12071
                {
0
12072
                    AllocatorType<object_t> alloc;
0
12073
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
0
12074
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
0
12075
                    break;
0
12076
                }
0
12077
0
12078
                case value_t::array:
0
12079
                {
0
12080
                    AllocatorType<array_t> alloc;
0
12081
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
0
12082
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
0
12083
                    break;
0
12084
                }
0
12085
0
12086
                case value_t::string:
0
12087
                {
0
12088
                    AllocatorType<string_t> alloc;
0
12089
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
0
12090
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
0
12091
                    break;
0
12092
                }
0
12093
0
12094
                default:
0
12095
                {
0
12096
                    break;
0
12097
                }
0
12098
            }
0
12099
        }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE10json_value7destroyENS_6detail7value_tE
173k
12067
        {
173k
12068
            switch (t)
173k
12069
            {
18.3k
12070
                case value_t::object:
18.3k
12071
                {
18.3k
12072
                    AllocatorType<object_t> alloc;
18.3k
12073
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
18.3k
12074
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
18.3k
12075
                    break;
18.3k
12076
                }
18.3k
12077
202
12078
                case value_t::array:
202
12079
                {
202
12080
                    AllocatorType<array_t> alloc;
202
12081
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
202
12082
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
202
12083
                    break;
18.3k
12084
                }
18.3k
12085
28.7k
12086
                case value_t::string:
28.7k
12087
                {
28.7k
12088
                    AllocatorType<string_t> alloc;
28.7k
12089
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
28.7k
12090
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
28.7k
12091
                    break;
18.3k
12092
                }
18.3k
12093
126k
12094
                default:
126k
12095
                {
126k
12096
                    break;
18.3k
12097
                }
173k
12098
            }
173k
12099
        }
12100
    };
12101
12102
    /*!
12103
    @brief checks the class invariants
12104
12105
    This function asserts the class invariants. It needs to be called at the
12106
    end of every constructor to make sure that created objects respect the
12107
    invariant. Furthermore, it has to be called each time the type of a JSON
12108
    value is changed, because the invariant expresses a relationship between
12109
    @a m_type and @a m_value.
12110
    */
12111
    void assert_invariant() const noexcept
652k
12112
    {
652k
12113
        assert(m_type != value_t::object or m_value.object != nullptr);
652k
12114
        assert(m_type != value_t::array or m_value.array != nullptr);
652k
12115
        assert(m_type != value_t::string or m_value.string != nullptr);
652k
12116
    }
12117
12118
  public:
12119
    //////////////////////////
12120
    // JSON parser callback //
12121
    //////////////////////////
12122
12123
    /*!
12124
    @brief parser event types
12125
12126
    The parser callback distinguishes the following events:
12127
    - `object_start`: the parser read `{` and started to process a JSON object
12128
    - `key`: the parser read a key of a value in an object
12129
    - `object_end`: the parser read `}` and finished processing a JSON object
12130
    - `array_start`: the parser read `[` and started to process a JSON array
12131
    - `array_end`: the parser read `]` and finished processing a JSON array
12132
    - `value`: the parser finished reading a JSON value
12133
12134
    @image html callback_events.png "Example when certain parse events are triggered"
12135
12136
    @sa @ref parser_callback_t for more information and examples
12137
    */
12138
    using parse_event_t = typename parser::parse_event_t;
12139
12140
    /*!
12141
    @brief per-element parser callback type
12142
12143
    With a parser callback function, the result of parsing a JSON text can be
12144
    influenced. When passed to @ref parse, it is called on certain events
12145
    (passed as @ref parse_event_t via parameter @a event) with a set recursion
12146
    depth @a depth and context JSON value @a parsed. The return value of the
12147
    callback function is a boolean indicating whether the element that emitted
12148
    the callback shall be kept or not.
12149
12150
    We distinguish six scenarios (determined by the event type) in which the
12151
    callback function can be called. The following table describes the values
12152
    of the parameters @a depth, @a event, and @a parsed.
12153
12154
    parameter @a event | description | parameter @a depth | parameter @a parsed
12155
    ------------------ | ----------- | ------------------ | -------------------
12156
    parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded
12157
    parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key
12158
    parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object
12159
    parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded
12160
    parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
12161
    parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
12162
12163
    @image html callback_events.png "Example when certain parse events are triggered"
12164
12165
    Discarding a value (i.e., returning `false`) has different effects
12166
    depending on the context in which function was called:
12167
12168
    - Discarded values in structured types are skipped. That is, the parser
12169
      will behave as if the discarded value was never read.
12170
    - In case a value outside a structured type is skipped, it is replaced
12171
      with `null`. This case happens if the top-level element is skipped.
12172
12173
    @param[in] depth  the depth of the recursion during parsing
12174
12175
    @param[in] event  an event of type parse_event_t indicating the context in
12176
    the callback function has been called
12177
12178
    @param[in,out] parsed  the current intermediate parse result; note that
12179
    writing to this value has no effect for parse_event_t::key events
12180
12181
    @return Whether the JSON value which called the function during parsing
12182
    should be kept (`true`) or not (`false`). In the latter case, it is either
12183
    skipped completely or replaced by an empty discarded object.
12184
12185
    @sa @ref parse for examples
12186
12187
    @since version 1.0.0
12188
    */
12189
    using parser_callback_t = typename parser::parser_callback_t;
12190
12191
    //////////////////
12192
    // constructors //
12193
    //////////////////
12194
12195
    /// @name constructors and destructors
12196
    /// Constructors of class @ref basic_json, copy/move constructor, copy
12197
    /// assignment, static functions creating objects, and the destructor.
12198
    /// @{
12199
12200
    /*!
12201
    @brief create an empty value with a given type
12202
12203
    Create an empty JSON value with a given type. The value will be default
12204
    initialized with an empty value which depends on the type:
12205
12206
    Value type  | initial value
12207
    ----------- | -------------
12208
    null        | `null`
12209
    boolean     | `false`
12210
    string      | `""`
12211
    number      | `0`
12212
    object      | `{}`
12213
    array       | `[]`
12214
12215
    @param[in] v  the type of the value to create
12216
12217
    @complexity Constant.
12218
12219
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12220
    changes to any JSON value.
12221
12222
    @liveexample{The following code shows the constructor for different @ref
12223
    value_t values,basic_json__value_t}
12224
12225
    @sa @ref clear() -- restores the postcondition of this constructor
12226
12227
    @since version 1.0.0
12228
    */
12229
    basic_json(const value_t v)
12230
        : m_type(v), m_value(v)
88.8k
12231
    {
88.8k
12232
        assert_invariant();
88.8k
12233
    }
12234
12235
    /*!
12236
    @brief create a null object
12237
12238
    Create a `null` JSON value. It either takes a null pointer as parameter
12239
    (explicitly creating `null`) or no parameter (implicitly creating `null`).
12240
    The passed null pointer itself is not read -- it is only used to choose
12241
    the right constructor.
12242
12243
    @complexity Constant.
12244
12245
    @exceptionsafety No-throw guarantee: this constructor never throws
12246
    exceptions.
12247
12248
    @liveexample{The following code shows the constructor with and without a
12249
    null pointer parameter.,basic_json__nullptr_t}
12250
12251
    @since version 1.0.0
12252
    */
12253
    basic_json(std::nullptr_t = nullptr) noexcept
12254
        : basic_json(value_t::null)
73.7k
12255
    {
73.7k
12256
        assert_invariant();
73.7k
12257
    }
12258
12259
    /*!
12260
    @brief create a JSON value
12261
12262
    This is a "catch all" constructor for all compatible JSON types; that is,
12263
    types for which a `to_json()` method exists. The constructor forwards the
12264
    parameter @a val to that method (to `json_serializer<U>::to_json` method
12265
    with `U = uncvref_t<CompatibleType>`, to be exact).
12266
12267
    Template type @a CompatibleType includes, but is not limited to, the
12268
    following types:
12269
    - **arrays**: @ref array_t and all kinds of compatible containers such as
12270
      `std::vector`, `std::deque`, `std::list`, `std::forward_list`,
12271
      `std::array`, `std::valarray`, `std::set`, `std::unordered_set`,
12272
      `std::multiset`, and `std::unordered_multiset` with a `value_type` from
12273
      which a @ref basic_json value can be constructed.
12274
    - **objects**: @ref object_t and all kinds of compatible associative
12275
      containers such as `std::map`, `std::unordered_map`, `std::multimap`,
12276
      and `std::unordered_multimap` with a `key_type` compatible to
12277
      @ref string_t and a `value_type` from which a @ref basic_json value can
12278
      be constructed.
12279
    - **strings**: @ref string_t, string literals, and all compatible string
12280
      containers can be used.
12281
    - **numbers**: @ref number_integer_t, @ref number_unsigned_t,
12282
      @ref number_float_t, and all convertible number types such as `int`,
12283
      `size_t`, `int64_t`, `float` or `double` can be used.
12284
    - **boolean**: @ref boolean_t / `bool` can be used.
12285
12286
    See the examples below.
12287
12288
    @tparam CompatibleType a type such that:
12289
    - @a CompatibleType is not derived from `std::istream`,
12290
    - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move
12291
         constructors),
12292
    - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments)
12293
    - @a CompatibleType is not a @ref basic_json nested type (e.g.,
12294
         @ref json_pointer, @ref iterator, etc ...)
12295
    - @ref @ref json_serializer<U> has a
12296
         `to_json(basic_json_t&, CompatibleType&&)` method
12297
12298
    @tparam U = `uncvref_t<CompatibleType>`
12299
12300
    @param[in] val the value to be forwarded to the respective constructor
12301
12302
    @complexity Usually linear in the size of the passed @a val, also
12303
                depending on the implementation of the called `to_json()`
12304
                method.
12305
12306
    @exceptionsafety Depends on the called constructor. For types directly
12307
    supported by the library (i.e., all types for which no `to_json()` function
12308
    was provided), strong guarantee holds: if an exception is thrown, there are
12309
    no changes to any JSON value.
12310
12311
    @liveexample{The following code shows the constructor with several
12312
    compatible types.,basic_json__CompatibleType}
12313
12314
    @since version 2.1.0
12315
    */
12316
    template <typename CompatibleType,
12317
              typename U = detail::uncvref_t<CompatibleType>,
12318
              detail::enable_if_t<
12319
                  not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0>
12320
    basic_json(CompatibleType && val) noexcept(noexcept(
12321
                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
12322
                                           std::forward<CompatibleType>(val))))
60.9k
12323
    {
60.9k
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
60.9k
12325
        assert_invariant();
60.9k
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IddLi0EEEOT_
1
12323
    {
1
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
1
12325
        assert_invariant();
1
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IKS8_S8_Li0EEEOT_
16
12323
    {
16
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
16
12325
        assert_invariant();
16
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRjjLi0EEEOT_
48
12323
    {
48
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
48
12325
        assert_invariant();
48
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRKPKcSD_Li0EEEOT_
10
12323
    {
10
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
10
12325
        assert_invariant();
10
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IbbLi0EEEOT_
1
12323
    {
1
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
1
12325
        assert_invariant();
1
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IS8_S8_Li0EEEOT_
144
12323
    {
144
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
144
12325
        assert_invariant();
144
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRA6_KcA6_cLi0EEEOT_
1
12323
    {
1
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
1
12325
        assert_invariant();
1
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IiiLi0EEEOT_
1
12323
    {
1
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
1
12325
        assert_invariant();
1
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRS8_S8_Li0EEEOT_
18.3k
12323
    {
18.3k
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
18.3k
12325
        assert_invariant();
18.3k
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRddLi0EEEOT_
16.8k
12323
    {
16.8k
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
16.8k
12325
        assert_invariant();
16.8k
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRbbLi0EEEOT_
179
12323
    {
179
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
179
12325
        assert_invariant();
179
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRllLi0EEEOT_
2.69k
12323
    {
2.69k
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
2.69k
12325
        assert_invariant();
2.69k
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRmmLi0EEEOT_
22.6k
12323
    {
22.6k
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
22.6k
12325
        assert_invariant();
22.6k
12326
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRA474_KcA474_cLi0EEEOT_
58
12323
    {
58
12324
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
58
12325
        assert_invariant();
58
12326
    }
12327
12328
    /*!
12329
    @brief create a JSON value from an existing one
12330
12331
    This is a constructor for existing @ref basic_json types.
12332
    It does not hijack copy/move constructors, since the parameter has different
12333
    template arguments than the current ones.
12334
12335
    The constructor tries to convert the internal @ref m_value of the parameter.
12336
12337
    @tparam BasicJsonType a type such that:
12338
    - @a BasicJsonType is a @ref basic_json type.
12339
    - @a BasicJsonType has different template arguments than @ref basic_json_t.
12340
12341
    @param[in] val the @ref basic_json value to be converted.
12342
12343
    @complexity Usually linear in the size of the passed @a val, also
12344
                depending on the implementation of the called `to_json()`
12345
                method.
12346
12347
    @exceptionsafety Depends on the called constructor. For types directly
12348
    supported by the library (i.e., all types for which no `to_json()` function
12349
    was provided), strong guarantee holds: if an exception is thrown, there are
12350
    no changes to any JSON value.
12351
12352
    @since version 3.2.0
12353
    */
12354
    template <typename BasicJsonType,
12355
              detail::enable_if_t<
12356
                  detail::is_basic_json<BasicJsonType>::value and not std::is_same<basic_json, BasicJsonType>::value, int> = 0>
12357
    basic_json(const BasicJsonType& val)
12358
    {
12359
        using other_boolean_t = typename BasicJsonType::boolean_t;
12360
        using other_number_float_t = typename BasicJsonType::number_float_t;
12361
        using other_number_integer_t = typename BasicJsonType::number_integer_t;
12362
        using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
12363
        using other_string_t = typename BasicJsonType::string_t;
12364
        using other_object_t = typename BasicJsonType::object_t;
12365
        using other_array_t = typename BasicJsonType::array_t;
12366
12367
        switch (val.type())
12368
        {
12369
            case value_t::boolean:
12370
                JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
12371
                break;
12372
            case value_t::number_float:
12373
                JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
12374
                break;
12375
            case value_t::number_integer:
12376
                JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
12377
                break;
12378
            case value_t::number_unsigned:
12379
                JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
12380
                break;
12381
            case value_t::string:
12382
                JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
12383
                break;
12384
            case value_t::object:
12385
                JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
12386
                break;
12387
            case value_t::array:
12388
                JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
12389
                break;
12390
            case value_t::null:
12391
                *this = nullptr;
12392
                break;
12393
            case value_t::discarded:
12394
                m_type = value_t::discarded;
12395
                break;
12396
        }
12397
        assert_invariant();
12398
    }
12399
12400
    /*!
12401
    @brief create a container (array or object) from an initializer list
12402
12403
    Creates a JSON value of type array or object from the passed initializer
12404
    list @a init. In case @a type_deduction is `true` (default), the type of
12405
    the JSON value to be created is deducted from the initializer list @a init
12406
    according to the following rules:
12407
12408
    1. If the list is empty, an empty JSON object value `{}` is created.
12409
    2. If the list consists of pairs whose first element is a string, a JSON
12410
       object value is created where the first elements of the pairs are
12411
       treated as keys and the second elements are as values.
12412
    3. In all other cases, an array is created.
12413
12414
    The rules aim to create the best fit between a C++ initializer list and
12415
    JSON values. The rationale is as follows:
12416
12417
    1. The empty initializer list is written as `{}` which is exactly an empty
12418
       JSON object.
12419
    2. C++ has no way of describing mapped types other than to list a list of
12420
       pairs. As JSON requires that keys must be of type string, rule 2 is the
12421
       weakest constraint one can pose on initializer lists to interpret them
12422
       as an object.
12423
    3. In all other cases, the initializer list could not be interpreted as
12424
       JSON object type, so interpreting it as JSON array type is safe.
12425
12426
    With the rules described above, the following JSON values cannot be
12427
    expressed by an initializer list:
12428
12429
    - the empty array (`[]`): use @ref array(initializer_list_t)
12430
      with an empty initializer list in this case
12431
    - arrays whose elements satisfy rule 2: use @ref
12432
      array(initializer_list_t) with the same initializer list
12433
      in this case
12434
12435
    @note When used without parentheses around an empty initializer list, @ref
12436
    basic_json() is called instead of this function, yielding the JSON null
12437
    value.
12438
12439
    @param[in] init  initializer list with JSON values
12440
12441
    @param[in] type_deduction internal parameter; when set to `true`, the type
12442
    of the JSON value is deducted from the initializer list @a init; when set
12443
    to `false`, the type provided via @a manual_type is forced. This mode is
12444
    used by the functions @ref array(initializer_list_t) and
12445
    @ref object(initializer_list_t).
12446
12447
    @param[in] manual_type internal parameter; when @a type_deduction is set
12448
    to `false`, the created JSON value will use the provided type (only @ref
12449
    value_t::array and @ref value_t::object are valid); when @a type_deduction
12450
    is set to `true`, this parameter has no effect
12451
12452
    @throw type_error.301 if @a type_deduction is `false`, @a manual_type is
12453
    `value_t::object`, but @a init contains an element which is not a pair
12454
    whose first element is a string. In this case, the constructor could not
12455
    create an object. If @a type_deduction would have be `true`, an array
12456
    would have been created. See @ref object(initializer_list_t)
12457
    for an example.
12458
12459
    @complexity Linear in the size of the initializer list @a init.
12460
12461
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12462
    changes to any JSON value.
12463
12464
    @liveexample{The example below shows how JSON values are created from
12465
    initializer lists.,basic_json__list_init_t}
12466
12467
    @sa @ref array(initializer_list_t) -- create a JSON array
12468
    value from an initializer list
12469
    @sa @ref object(initializer_list_t) -- create a JSON object
12470
    value from an initializer list
12471
12472
    @since version 1.0.0
12473
    */
12474
    basic_json(initializer_list_t init,
12475
               bool type_deduction = true,
12476
               value_t manual_type = value_t::array)
12477
    {
12478
        // check if each element is an array with two elements whose first
12479
        // element is a string
12480
        bool is_an_object = std::all_of(init.begin(), init.end(),
12481
                                        [](const detail::json_ref<basic_json>& element_ref)
12482
        {
12483
            return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string());
12484
        });
12485
12486
        // adjust type if type deduction is not wanted
12487
        if (not type_deduction)
12488
        {
12489
            // if array is wanted, do not create an object though possible
12490
            if (manual_type == value_t::array)
12491
            {
12492
                is_an_object = false;
12493
            }
12494
12495
            // if object is wanted but impossible, throw an exception
12496
            if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object))
12497
            {
12498
                JSON_THROW(type_error::create(301, "cannot create object from initializer list"));
12499
            }
12500
        }
12501
12502
        if (is_an_object)
12503
        {
12504
            // the initializer list is a list of pairs -> create object
12505
            m_type = value_t::object;
12506
            m_value = value_t::object;
12507
12508
            std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)
12509
            {
12510
                auto element = element_ref.moved_or_copied();
12511
                m_value.object->emplace(
12512
                    std::move(*((*element.m_value.array)[0].m_value.string)),
12513
                    std::move((*element.m_value.array)[1]));
12514
            });
12515
        }
12516
        else
12517
        {
12518
            // the initializer list describes an array -> create array
12519
            m_type = value_t::array;
12520
            m_value.array = create<array_t>(init.begin(), init.end());
12521
        }
12522
12523
        assert_invariant();
12524
    }
12525
12526
    /*!
12527
    @brief explicitly create an array from an initializer list
12528
12529
    Creates a JSON array value from a given initializer list. That is, given a
12530
    list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
12531
    initializer list is empty, the empty array `[]` is created.
12532
12533
    @note This function is only needed to express two edge cases that cannot
12534
    be realized with the initializer list constructor (@ref
12535
    basic_json(initializer_list_t, bool, value_t)). These cases
12536
    are:
12537
    1. creating an array whose elements are all pairs whose first element is a
12538
    string -- in this case, the initializer list constructor would create an
12539
    object, taking the first elements as keys
12540
    2. creating an empty array -- passing the empty initializer list to the
12541
    initializer list constructor yields an empty object
12542
12543
    @param[in] init  initializer list with JSON values to create an array from
12544
    (optional)
12545
12546
    @return JSON array value
12547
12548
    @complexity Linear in the size of @a init.
12549
12550
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12551
    changes to any JSON value.
12552
12553
    @liveexample{The following code shows an example for the `array`
12554
    function.,array}
12555
12556
    @sa @ref basic_json(initializer_list_t, bool, value_t) --
12557
    create a JSON value from an initializer list
12558
    @sa @ref object(initializer_list_t) -- create a JSON object
12559
    value from an initializer list
12560
12561
    @since version 1.0.0
12562
    */
12563
    static basic_json array(initializer_list_t init = {})
12564
    {
12565
        return basic_json(init, false, value_t::array);
12566
    }
12567
12568
    /*!
12569
    @brief explicitly create an object from an initializer list
12570
12571
    Creates a JSON object value from a given initializer list. The initializer
12572
    lists elements must be pairs, and their first elements must be strings. If
12573
    the initializer list is empty, the empty object `{}` is created.
12574
12575
    @note This function is only added for symmetry reasons. In contrast to the
12576
    related function @ref array(initializer_list_t), there are
12577
    no cases which can only be expressed by this function. That is, any
12578
    initializer list @a init can also be passed to the initializer list
12579
    constructor @ref basic_json(initializer_list_t, bool, value_t).
12580
12581
    @param[in] init  initializer list to create an object from (optional)
12582
12583
    @return JSON object value
12584
12585
    @throw type_error.301 if @a init is not a list of pairs whose first
12586
    elements are strings. In this case, no object can be created. When such a
12587
    value is passed to @ref basic_json(initializer_list_t, bool, value_t),
12588
    an array would have been created from the passed initializer list @a init.
12589
    See example below.
12590
12591
    @complexity Linear in the size of @a init.
12592
12593
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12594
    changes to any JSON value.
12595
12596
    @liveexample{The following code shows an example for the `object`
12597
    function.,object}
12598
12599
    @sa @ref basic_json(initializer_list_t, bool, value_t) --
12600
    create a JSON value from an initializer list
12601
    @sa @ref array(initializer_list_t) -- create a JSON array
12602
    value from an initializer list
12603
12604
    @since version 1.0.0
12605
    */
12606
    static basic_json object(initializer_list_t init = {})
12607
    {
12608
        return basic_json(init, false, value_t::object);
12609
    }
12610
12611
    /*!
12612
    @brief construct an array with count copies of given value
12613
12614
    Constructs a JSON array value by creating @a cnt copies of a passed value.
12615
    In case @a cnt is `0`, an empty array is created.
12616
12617
    @param[in] cnt  the number of JSON copies of @a val to create
12618
    @param[in] val  the JSON value to copy
12619
12620
    @post `std::distance(begin(),end()) == cnt` holds.
12621
12622
    @complexity Linear in @a cnt.
12623
12624
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12625
    changes to any JSON value.
12626
12627
    @liveexample{The following code shows examples for the @ref
12628
    basic_json(size_type\, const basic_json&)
12629
    constructor.,basic_json__size_type_basic_json}
12630
12631
    @since version 1.0.0
12632
    */
12633
    basic_json(size_type cnt, const basic_json& val)
12634
        : m_type(value_t::array)
12635
    {
12636
        m_value.array = create<array_t>(cnt, val);
12637
        assert_invariant();
12638
    }
12639
12640
    /*!
12641
    @brief construct a JSON container given an iterator range
12642
12643
    Constructs the JSON value with the contents of the range `[first, last)`.
12644
    The semantics depends on the different types a JSON value can have:
12645
    - In case of a null type, invalid_iterator.206 is thrown.
12646
    - In case of other primitive types (number, boolean, or string), @a first
12647
      must be `begin()` and @a last must be `end()`. In this case, the value is
12648
      copied. Otherwise, invalid_iterator.204 is thrown.
12649
    - In case of structured types (array, object), the constructor behaves as
12650
      similar versions for `std::vector` or `std::map`; that is, a JSON array
12651
      or object is constructed from the values in the range.
12652
12653
    @tparam InputIT an input iterator type (@ref iterator or @ref
12654
    const_iterator)
12655
12656
    @param[in] first begin of the range to copy from (included)
12657
    @param[in] last end of the range to copy from (excluded)
12658
12659
    @pre Iterators @a first and @a last must be initialized. **This
12660
         precondition is enforced with an assertion (see warning).** If
12661
         assertions are switched off, a violation of this precondition yields
12662
         undefined behavior.
12663
12664
    @pre Range `[first, last)` is valid. Usually, this precondition cannot be
12665
         checked efficiently. Only certain edge cases are detected; see the
12666
         description of the exceptions below. A violation of this precondition
12667
         yields undefined behavior.
12668
12669
    @warning A precondition is enforced with a runtime assertion that will
12670
             result in calling `std::abort` if this precondition is not met.
12671
             Assertions can be disabled by defining `NDEBUG` at compile time.
12672
             See https://en.cppreference.com/w/cpp/error/assert for more
12673
             information.
12674
12675
    @throw invalid_iterator.201 if iterators @a first and @a last are not
12676
    compatible (i.e., do not belong to the same JSON value). In this case,
12677
    the range `[first, last)` is undefined.
12678
    @throw invalid_iterator.204 if iterators @a first and @a last belong to a
12679
    primitive type (number, boolean, or string), but @a first does not point
12680
    to the first element any more. In this case, the range `[first, last)` is
12681
    undefined. See example code below.
12682
    @throw invalid_iterator.206 if iterators @a first and @a last belong to a
12683
    null value. In this case, the range `[first, last)` is undefined.
12684
12685
    @complexity Linear in distance between @a first and @a last.
12686
12687
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12688
    changes to any JSON value.
12689
12690
    @liveexample{The example below shows several ways to create JSON values by
12691
    specifying a subrange with iterators.,basic_json__InputIt_InputIt}
12692
12693
    @since version 1.0.0
12694
    */
12695
    template<class InputIT, typename std::enable_if<
12696
                 std::is_same<InputIT, typename basic_json_t::iterator>::value or
12697
                 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
12698
    basic_json(InputIT first, InputIT last)
12699
    {
12700
        assert(first.m_object != nullptr);
12701
        assert(last.m_object != nullptr);
12702
12703
        // make sure iterator fits the current value
12704
        if (JSON_UNLIKELY(first.m_object != last.m_object))
12705
        {
12706
            JSON_THROW(invalid_iterator::create(201, "iterators are not compatible"));
12707
        }
12708
12709
        // copy type from first iterator
12710
        m_type = first.m_object->m_type;
12711
12712
        // check if iterator range is complete for primitive values
12713
        switch (m_type)
12714
        {
12715
            case value_t::boolean:
12716
            case value_t::number_float:
12717
            case value_t::number_integer:
12718
            case value_t::number_unsigned:
12719
            case value_t::string:
12720
            {
12721
                if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin()
12722
                                  or not last.m_it.primitive_iterator.is_end()))
12723
                {
12724
                    JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
12725
                }
12726
                break;
12727
            }
12728
12729
            default:
12730
                break;
12731
        }
12732
12733
        switch (m_type)
12734
        {
12735
            case value_t::number_integer:
12736
            {
12737
                m_value.number_integer = first.m_object->m_value.number_integer;
12738
                break;
12739
            }
12740
12741
            case value_t::number_unsigned:
12742
            {
12743
                m_value.number_unsigned = first.m_object->m_value.number_unsigned;
12744
                break;
12745
            }
12746
12747
            case value_t::number_float:
12748
            {
12749
                m_value.number_float = first.m_object->m_value.number_float;
12750
                break;
12751
            }
12752
12753
            case value_t::boolean:
12754
            {
12755
                m_value.boolean = first.m_object->m_value.boolean;
12756
                break;
12757
            }
12758
12759
            case value_t::string:
12760
            {
12761
                m_value = *first.m_object->m_value.string;
12762
                break;
12763
            }
12764
12765
            case value_t::object:
12766
            {
12767
                m_value.object = create<object_t>(first.m_it.object_iterator,
12768
                                                  last.m_it.object_iterator);
12769
                break;
12770
            }
12771
12772
            case value_t::array:
12773
            {
12774
                m_value.array = create<array_t>(first.m_it.array_iterator,
12775
                                                last.m_it.array_iterator);
12776
                break;
12777
            }
12778
12779
            default:
12780
                JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " +
12781
                                                    std::string(first.m_object->type_name())));
12782
        }
12783
12784
        assert_invariant();
12785
    }
12786
12787
12788
    ///////////////////////////////////////
12789
    // other constructors and destructor //
12790
    ///////////////////////////////////////
12791
12792
    /// @private
12793
    basic_json(const detail::json_ref<basic_json>& ref)
12794
        : basic_json(ref.moved_or_copied())
12795
    {}
12796
12797
    /*!
12798
    @brief copy constructor
12799
12800
    Creates a copy of a given JSON value.
12801
12802
    @param[in] other  the JSON value to copy
12803
12804
    @post `*this == other`
12805
12806
    @complexity Linear in the size of @a other.
12807
12808
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12809
    changes to any JSON value.
12810
12811
    @requirement This function helps `basic_json` satisfying the
12812
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
12813
    requirements:
12814
    - The complexity is linear.
12815
    - As postcondition, it holds: `other == basic_json(other)`.
12816
12817
    @liveexample{The following code shows an example for the copy
12818
    constructor.,basic_json__basic_json}
12819
12820
    @since version 1.0.0
12821
    */
12822
    basic_json(const basic_json& other)
12823
        : m_type(other.m_type)
20.0k
12824
    {
20.0k
12825
        // check of passed value is valid
20.0k
12826
        other.assert_invariant();
20.0k
12827
20.0k
12828
        switch (m_type)
20.0k
12829
        {
3.24k
12830
            case value_t::object:
3.24k
12831
            {
3.24k
12832
                m_value = *other.m_value.object;
3.24k
12833
                break;
3.24k
12834
            }
3.24k
12835
24
12836
            case value_t::array:
24
12837
            {
24
12838
                m_value = *other.m_value.array;
24
12839
                break;
3.24k
12840
            }
3.24k
12841
10.1k
12842
            case value_t::string:
10.1k
12843
            {
10.1k
12844
                m_value = *other.m_value.string;
10.1k
12845
                break;
3.24k
12846
            }
3.24k
12847
12
12848
            case value_t::boolean:
12
12849
            {
12
12850
                m_value = other.m_value.boolean;
12
12851
                break;
3.24k
12852
            }
3.24k
12853
421
12854
            case value_t::number_integer:
421
12855
            {
421
12856
                m_value = other.m_value.number_integer;
421
12857
                break;
3.24k
12858
            }
3.24k
12859
3.57k
12860
            case value_t::number_unsigned:
3.57k
12861
            {
3.57k
12862
                m_value = other.m_value.number_unsigned;
3.57k
12863
                break;
3.24k
12864
            }
3.24k
12865
2.62k
12866
            case value_t::number_float:
2.62k
12867
            {
2.62k
12868
                m_value = other.m_value.number_float;
2.62k
12869
                break;
3.24k
12870
            }
3.24k
12871
8
12872
            default:
8
12873
                break;
20.0k
12874
        }
20.0k
12875
20.0k
12876
        assert_invariant();
20.0k
12877
    }
12878
12879
    /*!
12880
    @brief move constructor
12881
12882
    Move constructor. Constructs a JSON value with the contents of the given
12883
    value @a other using move semantics. It "steals" the resources from @a
12884
    other and leaves it as JSON null value.
12885
12886
    @param[in,out] other  value to move to this object
12887
12888
    @post `*this` has the same value as @a other before the call.
12889
    @post @a other is a JSON null value.
12890
12891
    @complexity Constant.
12892
12893
    @exceptionsafety No-throw guarantee: this constructor never throws
12894
    exceptions.
12895
12896
    @requirement This function helps `basic_json` satisfying the
12897
    [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible)
12898
    requirements.
12899
12900
    @liveexample{The code below shows the move constructor explicitly called
12901
    via std::move.,basic_json__moveconstructor}
12902
12903
    @since version 1.0.0
12904
    */
12905
    basic_json(basic_json&& other) noexcept
12906
        : m_type(std::move(other.m_type)),
12907
          m_value(std::move(other.m_value))
3.62k
12908
    {
3.62k
12909
        // check that passed value is valid
3.62k
12910
        other.assert_invariant();
3.62k
12911
3.62k
12912
        // invalidate payload
3.62k
12913
        other.m_type = value_t::null;
3.62k
12914
        other.m_value = {};
3.62k
12915
3.62k
12916
        assert_invariant();
3.62k
12917
    }
12918
12919
    /*!
12920
    @brief copy assignment
12921
12922
    Copy assignment operator. Copies a JSON value via the "copy and swap"
12923
    strategy: It is expressed in terms of the copy constructor, destructor,
12924
    and the `swap()` member function.
12925
12926
    @param[in] other  value to copy from
12927
12928
    @complexity Linear.
12929
12930
    @requirement This function helps `basic_json` satisfying the
12931
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
12932
    requirements:
12933
    - The complexity is linear.
12934
12935
    @liveexample{The code below shows and example for the copy assignment. It
12936
    creates a copy of value `a` which is then swapped with `b`. Finally\, the
12937
    copy of `a` (which is the null value after the swap) is
12938
    destroyed.,basic_json__copyassignment}
12939
12940
    @since version 1.0.0
12941
    */
12942
    reference& operator=(basic_json other) noexcept (
12943
        std::is_nothrow_move_constructible<value_t>::value and
12944
        std::is_nothrow_move_assignable<value_t>::value and
12945
        std::is_nothrow_move_constructible<json_value>::value and
12946
        std::is_nothrow_move_assignable<json_value>::value
12947
    )
73.4k
12948
    {
73.4k
12949
        // check that passed value is valid
73.4k
12950
        other.assert_invariant();
73.4k
12951
73.4k
12952
        using std::swap;
73.4k
12953
        swap(m_type, other.m_type);
73.4k
12954
        swap(m_value, other.m_value);
73.4k
12955
73.4k
12956
        assert_invariant();
73.4k
12957
        return *this;
73.4k
12958
    }
12959
12960
    /*!
12961
    @brief destructor
12962
12963
    Destroys the JSON value and frees all allocated memory.
12964
12965
    @complexity Linear.
12966
12967
    @requirement This function helps `basic_json` satisfying the
12968
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
12969
    requirements:
12970
    - The complexity is linear.
12971
    - All stored elements are destroyed and all memory is freed.
12972
12973
    @since version 1.0.0
12974
    */
12975
    ~basic_json() noexcept
173k
12976
    {
173k
12977
        assert_invariant();
173k
12978
        m_value.destroy(m_type);
173k
12979
    }
12980
12981
    /// @}
12982
12983
  public:
12984
    ///////////////////////
12985
    // object inspection //
12986
    ///////////////////////
12987
12988
    /// @name object inspection
12989
    /// Functions to inspect the type of a JSON value.
12990
    /// @{
12991
12992
    /*!
12993
    @brief serialization
12994
12995
    Serialization function for JSON values. The function tries to mimic
12996
    Python's `json.dumps()` function, and currently supports its @a indent
12997
    and @a ensure_ascii parameters.
12998
12999
    @param[in] indent If indent is nonnegative, then array elements and object
13000
    members will be pretty-printed with that indent level. An indent level of
13001
    `0` will only insert newlines. `-1` (the default) selects the most compact
13002
    representation.
13003
    @param[in] indent_char The character to use for indentation if @a indent is
13004
    greater than `0`. The default is ` ` (space).
13005
    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters
13006
    in the output are escaped with `\uXXXX` sequences, and the result consists
13007
    of ASCII characters only.
13008
13009
    @return string containing the serialization of the JSON value
13010
13011
    @throw type_error.316 if a string stored inside the JSON value is not
13012
                          UTF-8 encoded
13013
13014
    @complexity Linear.
13015
13016
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
13017
    changes in the JSON value.
13018
13019
    @liveexample{The following example shows the effect of different @a indent\,
13020
    @a indent_char\, and @a ensure_ascii parameters to the result of the
13021
    serialization.,dump}
13022
13023
    @see https://docs.python.org/2/library/json.html#json.dump
13024
13025
    @since version 1.0.0; indentation character @a indent_char, option
13026
           @a ensure_ascii and exceptions added in version 3.0.0
13027
    */
13028
    string_t dump(const int indent = -1, const char indent_char = ' ',
13029
                  const bool ensure_ascii = false) const
15
13030
    {
15
13031
        string_t result;
15
13032
        serializer s(detail::output_adapter<char, string_t>(result), indent_char);
15
13033
15
13034
        if (indent >= 0)
15
13035
        {
15
13036
            s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
15
13037
        }
15
13038
        else
0
13039
        {
0
13040
            s.dump(*this, false, ensure_ascii, 0);
0
13041
        }
15
13042
15
13043
        return result;
15
13044
    }
13045
13046
    /*!
13047
    @brief return the type of the JSON value (explicit)
13048
13049
    Return the type of the JSON value as a value from the @ref value_t
13050
    enumeration.
13051
13052
    @return the type of the JSON value
13053
            Value type                | return value
13054
            ------------------------- | -------------------------
13055
            null                      | value_t::null
13056
            boolean                   | value_t::boolean
13057
            string                    | value_t::string
13058
            number (integer)          | value_t::number_integer
13059
            number (unsigned integer) | value_t::number_unsigned
13060
            number (floating-point)   | value_t::number_float
13061
            object                    | value_t::object
13062
            array                     | value_t::array
13063
            discarded                 | value_t::discarded
13064
13065
    @complexity Constant.
13066
13067
    @exceptionsafety No-throw guarantee: this member function never throws
13068
    exceptions.
13069
13070
    @liveexample{The following code exemplifies `type()` for all JSON
13071
    types.,type}
13072
13073
    @sa @ref operator value_t() -- return the type of the JSON value (implicit)
13074
    @sa @ref type_name() -- return the type as string
13075
13076
    @since version 1.0.0
13077
    */
13078
    constexpr value_t type() const noexcept
20
13079
    {
20
13080
        return m_type;
20
13081
    }
13082
13083
    /*!
13084
    @brief return whether type is primitive
13085
13086
    This function returns true if and only if the JSON type is primitive
13087
    (string, number, boolean, or null).
13088
13089
    @return `true` if type is primitive (string, number, boolean, or null),
13090
    `false` otherwise.
13091
13092
    @complexity Constant.
13093
13094
    @exceptionsafety No-throw guarantee: this member function never throws
13095
    exceptions.
13096
13097
    @liveexample{The following code exemplifies `is_primitive()` for all JSON
13098
    types.,is_primitive}
13099
13100
    @sa @ref is_structured() -- returns whether JSON value is structured
13101
    @sa @ref is_null() -- returns whether JSON value is `null`
13102
    @sa @ref is_string() -- returns whether JSON value is a string
13103
    @sa @ref is_boolean() -- returns whether JSON value is a boolean
13104
    @sa @ref is_number() -- returns whether JSON value is a number
13105
13106
    @since version 1.0.0
13107
    */
13108
    constexpr bool is_primitive() const noexcept
13109
    {
13110
        return is_null() or is_string() or is_boolean() or is_number();
13111
    }
13112
13113
    /*!
13114
    @brief return whether type is structured
13115
13116
    This function returns true if and only if the JSON type is structured
13117
    (array or object).
13118
13119
    @return `true` if type is structured (array or object), `false` otherwise.
13120
13121
    @complexity Constant.
13122
13123
    @exceptionsafety No-throw guarantee: this member function never throws
13124
    exceptions.
13125
13126
    @liveexample{The following code exemplifies `is_structured()` for all JSON
13127
    types.,is_structured}
13128
13129
    @sa @ref is_primitive() -- returns whether value is primitive
13130
    @sa @ref is_array() -- returns whether value is an array
13131
    @sa @ref is_object() -- returns whether value is an object
13132
13133
    @since version 1.0.0
13134
    */
13135
    constexpr bool is_structured() const noexcept
13136
    {
13137
        return is_array() or is_object();
13138
    }
13139
13140
    /*!
13141
    @brief return whether value is null
13142
13143
    This function returns true if and only if the JSON value is null.
13144
13145
    @return `true` if type is null, `false` otherwise.
13146
13147
    @complexity Constant.
13148
13149
    @exceptionsafety No-throw guarantee: this member function never throws
13150
    exceptions.
13151
13152
    @liveexample{The following code exemplifies `is_null()` for all JSON
13153
    types.,is_null}
13154
13155
    @since version 1.0.0
13156
    */
13157
    constexpr bool is_null() const noexcept
758
13158
    {
758
13159
        return (m_type == value_t::null);
758
13160
    }
13161
13162
    /*!
13163
    @brief return whether value is a boolean
13164
13165
    This function returns true if and only if the JSON value is a boolean.
13166
13167
    @return `true` if type is boolean, `false` otherwise.
13168
13169
    @complexity Constant.
13170
13171
    @exceptionsafety No-throw guarantee: this member function never throws
13172
    exceptions.
13173
13174
    @liveexample{The following code exemplifies `is_boolean()` for all JSON
13175
    types.,is_boolean}
13176
13177
    @since version 1.0.0
13178
    */
13179
    constexpr bool is_boolean() const noexcept
4
13180
    {
4
13181
        return (m_type == value_t::boolean);
4
13182
    }
13183
13184
    /*!
13185
    @brief return whether value is a number
13186
13187
    This function returns true if and only if the JSON value is a number. This
13188
    includes both integer (signed and unsigned) and floating-point values.
13189
13190
    @return `true` if type is number (regardless whether integer, unsigned
13191
    integer or floating-type), `false` otherwise.
13192
13193
    @complexity Constant.
13194
13195
    @exceptionsafety No-throw guarantee: this member function never throws
13196
    exceptions.
13197
13198
    @liveexample{The following code exemplifies `is_number()` for all JSON
13199
    types.,is_number}
13200
13201
    @sa @ref is_number_integer() -- check if value is an integer or unsigned
13202
    integer number
13203
    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
13204
    number
13205
    @sa @ref is_number_float() -- check if value is a floating-point number
13206
13207
    @since version 1.0.0
13208
    */
13209
    constexpr bool is_number() const noexcept
13210
    {
13211
        return is_number_integer() or is_number_float();
13212
    }
13213
13214
    /*!
13215
    @brief return whether value is an integer number
13216
13217
    This function returns true if and only if the JSON value is a signed or
13218
    unsigned integer number. This excludes floating-point values.
13219
13220
    @return `true` if type is an integer or unsigned integer number, `false`
13221
    otherwise.
13222
13223
    @complexity Constant.
13224
13225
    @exceptionsafety No-throw guarantee: this member function never throws
13226
    exceptions.
13227
13228
    @liveexample{The following code exemplifies `is_number_integer()` for all
13229
    JSON types.,is_number_integer}
13230
13231
    @sa @ref is_number() -- check if value is a number
13232
    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
13233
    number
13234
    @sa @ref is_number_float() -- check if value is a floating-point number
13235
13236
    @since version 1.0.0
13237
    */
13238
    constexpr bool is_number_integer() const noexcept
0
13239
    {
0
13240
        return (m_type == value_t::number_integer or m_type == value_t::number_unsigned);
0
13241
    }
13242
13243
    /*!
13244
    @brief return whether value is an unsigned integer number
13245
13246
    This function returns true if and only if the JSON value is an unsigned
13247
    integer number. This excludes floating-point and signed integer values.
13248
13249
    @return `true` if type is an unsigned integer number, `false` otherwise.
13250
13251
    @complexity Constant.
13252
13253
    @exceptionsafety No-throw guarantee: this member function never throws
13254
    exceptions.
13255
13256
    @liveexample{The following code exemplifies `is_number_unsigned()` for all
13257
    JSON types.,is_number_unsigned}
13258
13259
    @sa @ref is_number() -- check if value is a number
13260
    @sa @ref is_number_integer() -- check if value is an integer or unsigned
13261
    integer number
13262
    @sa @ref is_number_float() -- check if value is a floating-point number
13263
13264
    @since version 2.0.0
13265
    */
13266
    constexpr bool is_number_unsigned() const noexcept
152
13267
    {
152
13268
        return (m_type == value_t::number_unsigned);
152
13269
    }
13270
13271
    /*!
13272
    @brief return whether value is a floating-point number
13273
13274
    This function returns true if and only if the JSON value is a
13275
    floating-point number. This excludes signed and unsigned integer values.
13276
13277
    @return `true` if type is a floating-point number, `false` otherwise.
13278
13279
    @complexity Constant.
13280
13281
    @exceptionsafety No-throw guarantee: this member function never throws
13282
    exceptions.
13283
13284
    @liveexample{The following code exemplifies `is_number_float()` for all
13285
    JSON types.,is_number_float}
13286
13287
    @sa @ref is_number() -- check if value is number
13288
    @sa @ref is_number_integer() -- check if value is an integer number
13289
    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
13290
    number
13291
13292
    @since version 1.0.0
13293
    */
13294
    constexpr bool is_number_float() const noexcept
148
13295
    {
148
13296
        return (m_type == value_t::number_float);
148
13297
    }
13298
13299
    /*!
13300
    @brief return whether value is an object
13301
13302
    This function returns true if and only if the JSON value is an object.
13303
13304
    @return `true` if type is object, `false` otherwise.
13305
13306
    @complexity Constant.
13307
13308
    @exceptionsafety No-throw guarantee: this member function never throws
13309
    exceptions.
13310
13311
    @liveexample{The following code exemplifies `is_object()` for all JSON
13312
    types.,is_object}
13313
13314
    @since version 1.0.0
13315
    */
13316
    constexpr bool is_object() const noexcept
77.2k
13317
    {
77.2k
13318
        return (m_type == value_t::object);
77.2k
13319
    }
13320
13321
    /*!
13322
    @brief return whether value is an array
13323
13324
    This function returns true if and only if the JSON value is an array.
13325
13326
    @return `true` if type is array, `false` otherwise.
13327
13328
    @complexity Constant.
13329
13330
    @exceptionsafety No-throw guarantee: this member function never throws
13331
    exceptions.
13332
13333
    @liveexample{The following code exemplifies `is_array()` for all JSON
13334
    types.,is_array}
13335
13336
    @since version 1.0.0
13337
    */
13338
    constexpr bool is_array() const noexcept
150k
13339
    {
150k
13340
        return (m_type == value_t::array);
150k
13341
    }
13342
13343
    /*!
13344
    @brief return whether value is a string
13345
13346
    This function returns true if and only if the JSON value is a string.
13347
13348
    @return `true` if type is string, `false` otherwise.
13349
13350
    @complexity Constant.
13351
13352
    @exceptionsafety No-throw guarantee: this member function never throws
13353
    exceptions.
13354
13355
    @liveexample{The following code exemplifies `is_string()` for all JSON
13356
    types.,is_string}
13357
13358
    @since version 1.0.0
13359
    */
13360
    constexpr bool is_string() const noexcept
6.52k
13361
    {
6.52k
13362
        return (m_type == value_t::string);
6.52k
13363
    }
13364
13365
    /*!
13366
    @brief return whether value is discarded
13367
13368
    This function returns true if and only if the JSON value was discarded
13369
    during parsing with a callback function (see @ref parser_callback_t).
13370
13371
    @note This function will always be `false` for JSON values after parsing.
13372
    That is, discarded values can only occur during parsing, but will be
13373
    removed when inside a structured value or replaced by null in other cases.
13374
13375
    @return `true` if type is discarded, `false` otherwise.
13376
13377
    @complexity Constant.
13378
13379
    @exceptionsafety No-throw guarantee: this member function never throws
13380
    exceptions.
13381
13382
    @liveexample{The following code exemplifies `is_discarded()` for all JSON
13383
    types.,is_discarded}
13384
13385
    @since version 1.0.0
13386
    */
13387
    constexpr bool is_discarded() const noexcept
0
13388
    {
0
13389
        return (m_type == value_t::discarded);
0
13390
    }
13391
13392
    /*!
13393
    @brief return the type of the JSON value (implicit)
13394
13395
    Implicitly return the type of the JSON value as a value from the @ref
13396
    value_t enumeration.
13397
13398
    @return the type of the JSON value
13399
13400
    @complexity Constant.
13401
13402
    @exceptionsafety No-throw guarantee: this member function never throws
13403
    exceptions.
13404
13405
    @liveexample{The following code exemplifies the @ref value_t operator for
13406
    all JSON types.,operator__value_t}
13407
13408
    @sa @ref type() -- return the type of the JSON value (explicit)
13409
    @sa @ref type_name() -- return the type as string
13410
13411
    @since version 1.0.0
13412
    */
13413
    constexpr operator value_t() const noexcept
300
13414
    {
300
13415
        return m_type;
300
13416
    }
13417
13418
    /// @}
13419
13420
  private:
13421
    //////////////////
13422
    // value access //
13423
    //////////////////
13424
13425
    /// get a boolean (explicit)
13426
    boolean_t get_impl(boolean_t* /*unused*/) const
13427
    {
13428
        if (JSON_LIKELY(is_boolean()))
13429
        {
13430
            return m_value.boolean;
13431
        }
13432
13433
        JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name())));
13434
    }
13435
13436
    /// get a pointer to the value (object)
13437
    object_t* get_impl_ptr(object_t* /*unused*/) noexcept
13438
    {
13439
        return is_object() ? m_value.object : nullptr;
13440
    }
13441
13442
    /// get a pointer to the value (object)
13443
    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
13444
    {
13445
        return is_object() ? m_value.object : nullptr;
13446
    }
13447
13448
    /// get a pointer to the value (array)
13449
    array_t* get_impl_ptr(array_t* /*unused*/) noexcept
13450
    {
13451
        return is_array() ? m_value.array : nullptr;
13452
    }
13453
13454
    /// get a pointer to the value (array)
13455
    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
13456
    {
13457
        return is_array() ? m_value.array : nullptr;
13458
    }
13459
13460
    /// get a pointer to the value (string)
13461
    string_t* get_impl_ptr(string_t* /*unused*/) noexcept
13462
    {
13463
        return is_string() ? m_value.string : nullptr;
13464
    }
13465
13466
    /// get a pointer to the value (string)
13467
    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
3.26k
13468
    {
3.26k
13469
        return is_string() ? m_value.string : nullptr;
3.26k
13470
    }
13471
13472
    /// get a pointer to the value (boolean)
13473
    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
13474
    {
13475
        return is_boolean() ? &m_value.boolean : nullptr;
13476
    }
13477
13478
    /// get a pointer to the value (boolean)
13479
    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
2
13480
    {
2
13481
        return is_boolean() ? &m_value.boolean : nullptr;
2
13482
    }
13483
13484
    /// get a pointer to the value (integer number)
13485
    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
13486
    {
13487
        return is_number_integer() ? &m_value.number_integer : nullptr;
13488
    }
13489
13490
    /// get a pointer to the value (integer number)
13491
    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
0
13492
    {
0
13493
        return is_number_integer() ? &m_value.number_integer : nullptr;
0
13494
    }
13495
13496
    /// get a pointer to the value (unsigned number)
13497
    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
13498
    {
13499
        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
13500
    }
13501
13502
    /// get a pointer to the value (unsigned number)
13503
    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
152
13504
    {
152
13505
        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
152
13506
    }
13507
13508
    /// get a pointer to the value (floating-point number)
13509
    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
13510
    {
13511
        return is_number_float() ? &m_value.number_float : nullptr;
13512
    }
13513
13514
    /// get a pointer to the value (floating-point number)
13515
    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
148
13516
    {
148
13517
        return is_number_float() ? &m_value.number_float : nullptr;
148
13518
    }
13519
13520
    /*!
13521
    @brief helper function to implement get_ref()
13522
13523
    This function helps to implement get_ref() without code duplication for
13524
    const and non-const overloads
13525
13526
    @tparam ThisType will be deduced as `basic_json` or `const basic_json`
13527
13528
    @throw type_error.303 if ReferenceType does not match underlying value
13529
    type of the current JSON
13530
    */
13531
    template<typename ReferenceType, typename ThisType>
13532
    static ReferenceType get_ref_impl(ThisType& obj)
13533
    {
13534
        // delegate the call to get_ptr<>()
13535
        auto ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
13536
13537
        if (JSON_LIKELY(ptr != nullptr))
13538
        {
13539
            return *ptr;
13540
        }
13541
13542
        JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name())));
13543
    }
13544
13545
  public:
13546
    /// @name value access
13547
    /// Direct access to the stored value of a JSON value.
13548
    /// @{
13549
13550
    /*!
13551
    @brief get special-case overload
13552
13553
    This overloads avoids a lot of template boilerplate, it can be seen as the
13554
    identity method
13555
13556
    @tparam BasicJsonType == @ref basic_json
13557
13558
    @return a copy of *this
13559
13560
    @complexity Constant.
13561
13562
    @since version 2.1.0
13563
    */
13564
    template<typename BasicJsonType, detail::enable_if_t<
13565
                 std::is_same<typename std::remove_const<BasicJsonType>::type, basic_json_t>::value,
13566
                 int> = 0>
13567
    basic_json get() const
12
13568
    {
12
13569
        return *this;
12
13570
    }
13571
13572
    /*!
13573
    @brief get special-case overload
13574
13575
    This overloads converts the current @ref basic_json in a different
13576
    @ref basic_json type
13577
13578
    @tparam BasicJsonType == @ref basic_json
13579
13580
    @return a copy of *this, converted into @tparam BasicJsonType
13581
13582
    @complexity Depending on the implementation of the called `from_json()`
13583
                method.
13584
13585
    @since version 3.2.0
13586
    */
13587
    template<typename BasicJsonType, detail::enable_if_t<
13588
                 not std::is_same<BasicJsonType, basic_json>::value and
13589
                 detail::is_basic_json<BasicJsonType>::value, int> = 0>
13590
    BasicJsonType get() const
13591
    {
13592
        return *this;
13593
    }
13594
13595
    /*!
13596
    @brief get a value (explicit)
13597
13598
    Explicit type conversion between the JSON value and a compatible value
13599
    which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
13600
    and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
13601
    The value is converted by calling the @ref json_serializer<ValueType>
13602
    `from_json()` method.
13603
13604
    The function is equivalent to executing
13605
    @code {.cpp}
13606
    ValueType ret;
13607
    JSONSerializer<ValueType>::from_json(*this, ret);
13608
    return ret;
13609
    @endcode
13610
13611
    This overloads is chosen if:
13612
    - @a ValueType is not @ref basic_json,
13613
    - @ref json_serializer<ValueType> has a `from_json()` method of the form
13614
      `void from_json(const basic_json&, ValueType&)`, and
13615
    - @ref json_serializer<ValueType> does not have a `from_json()` method of
13616
      the form `ValueType from_json(const basic_json&)`
13617
13618
    @tparam ValueTypeCV the provided value type
13619
    @tparam ValueType the returned value type
13620
13621
    @return copy of the JSON value, converted to @a ValueType
13622
13623
    @throw what @ref json_serializer<ValueType> `from_json()` method throws
13624
13625
    @liveexample{The example below shows several conversions from JSON values
13626
    to other types. There a few things to note: (1) Floating-point numbers can
13627
    be converted to integers\, (2) A JSON array can be converted to a standard
13628
    `std::vector<short>`\, (3) A JSON object can be converted to C++
13629
    associative containers such as `std::unordered_map<std::string\,
13630
    json>`.,get__ValueType_const}
13631
13632
    @since version 2.1.0
13633
    */
13634
    template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
13635
             detail::enable_if_t <
13636
                 not detail::is_basic_json<ValueType>::value and
13637
                 detail::has_from_json<basic_json_t, ValueType>::value and
13638
                 not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
13639
                 int> = 0>
13640
    ValueType get() const noexcept(noexcept(
13641
                                       JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
3.56k
13642
    {
3.56k
13643
        // we cannot static_assert on ValueTypeCV being non-const, because
3.56k
13644
        // there is support for get<const basic_json_t>(), which is why we
3.56k
13645
        // still need the uncvref
3.56k
13646
        static_assert(not std::is_reference<ValueTypeCV>::value,
3.56k
13647
                      "get() cannot be used with reference types, you might want to use get_ref()");
3.56k
13648
        static_assert(std::is_default_constructible<ValueType>::value,
3.56k
13649
                      "types must be DefaultConstructible when used with get()");
3.56k
13650
3.56k
13651
        ValueType ret;
3.56k
13652
        JSONSerializer<ValueType>::from_json(*this, ret);
3.56k
13653
        return ret;
3.56k
13654
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE3getIddLi0EEET0_v
148
13642
    {
148
13643
        // we cannot static_assert on ValueTypeCV being non-const, because
148
13644
        // there is support for get<const basic_json_t>(), which is why we
148
13645
        // still need the uncvref
148
13646
        static_assert(not std::is_reference<ValueTypeCV>::value,
148
13647
                      "get() cannot be used with reference types, you might want to use get_ref()");
148
13648
        static_assert(std::is_default_constructible<ValueType>::value,
148
13649
                      "types must be DefaultConstructible when used with get()");
148
13650
148
13651
        ValueType ret;
148
13652
        JSONSerializer<ValueType>::from_json(*this, ret);
148
13653
        return ret;
148
13654
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE3getIiiLi0EEET0_v
152
13642
    {
152
13643
        // we cannot static_assert on ValueTypeCV being non-const, because
152
13644
        // there is support for get<const basic_json_t>(), which is why we
152
13645
        // still need the uncvref
152
13646
        static_assert(not std::is_reference<ValueTypeCV>::value,
152
13647
                      "get() cannot be used with reference types, you might want to use get_ref()");
152
13648
        static_assert(std::is_default_constructible<ValueType>::value,
152
13649
                      "types must be DefaultConstructible when used with get()");
152
13650
152
13651
        ValueType ret;
152
13652
        JSONSerializer<ValueType>::from_json(*this, ret);
152
13653
        return ret;
152
13654
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE3getIS8_S8_Li0EEET0_v
3.26k
13642
    {
3.26k
13643
        // we cannot static_assert on ValueTypeCV being non-const, because
3.26k
13644
        // there is support for get<const basic_json_t>(), which is why we
3.26k
13645
        // still need the uncvref
3.26k
13646
        static_assert(not std::is_reference<ValueTypeCV>::value,
3.26k
13647
                      "get() cannot be used with reference types, you might want to use get_ref()");
3.26k
13648
        static_assert(std::is_default_constructible<ValueType>::value,
3.26k
13649
                      "types must be DefaultConstructible when used with get()");
3.26k
13650
3.26k
13651
        ValueType ret;
3.26k
13652
        JSONSerializer<ValueType>::from_json(*this, ret);
3.26k
13653
        return ret;
3.26k
13654
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE3getIbbLi0EEET0_v
2
13642
    {
2
13643
        // we cannot static_assert on ValueTypeCV being non-const, because
2
13644
        // there is support for get<const basic_json_t>(), which is why we
2
13645
        // still need the uncvref
2
13646
        static_assert(not std::is_reference<ValueTypeCV>::value,
2
13647
                      "get() cannot be used with reference types, you might want to use get_ref()");
2
13648
        static_assert(std::is_default_constructible<ValueType>::value,
2
13649
                      "types must be DefaultConstructible when used with get()");
2
13650
2
13651
        ValueType ret;
2
13652
        JSONSerializer<ValueType>::from_json(*this, ret);
2
13653
        return ret;
2
13654
    }
13655
13656
    /*!
13657
    @brief get a value (explicit); special case
13658
13659
    Explicit type conversion between the JSON value and a compatible value
13660
    which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
13661
    and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
13662
    The value is converted by calling the @ref json_serializer<ValueType>
13663
    `from_json()` method.
13664
13665
    The function is equivalent to executing
13666
    @code {.cpp}
13667
    return JSONSerializer<ValueTypeCV>::from_json(*this);
13668
    @endcode
13669
13670
    This overloads is chosen if:
13671
    - @a ValueType is not @ref basic_json and
13672
    - @ref json_serializer<ValueType> has a `from_json()` method of the form
13673
      `ValueType from_json(const basic_json&)`
13674
13675
    @note If @ref json_serializer<ValueType> has both overloads of
13676
    `from_json()`, this one is chosen.
13677
13678
    @tparam ValueTypeCV the provided value type
13679
    @tparam ValueType the returned value type
13680
13681
    @return copy of the JSON value, converted to @a ValueType
13682
13683
    @throw what @ref json_serializer<ValueType> `from_json()` method throws
13684
13685
    @since version 2.1.0
13686
    */
13687
    template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
13688
             detail::enable_if_t<not std::is_same<basic_json_t, ValueType>::value and
13689
                                 detail::has_non_default_from_json<basic_json_t, ValueType>::value,
13690
                                 int> = 0>
13691
    ValueType get() const noexcept(noexcept(
13692
                                       JSONSerializer<ValueTypeCV>::from_json(std::declval<const basic_json_t&>())))
13693
    {
13694
        static_assert(not std::is_reference<ValueTypeCV>::value,
13695
                      "get() cannot be used with reference types, you might want to use get_ref()");
13696
        return JSONSerializer<ValueTypeCV>::from_json(*this);
13697
    }
13698
13699
    /*!
13700
    @brief get a pointer value (explicit)
13701
13702
    Explicit pointer access to the internally stored JSON value. No copies are
13703
    made.
13704
13705
    @warning The pointer becomes invalid if the underlying JSON object
13706
    changes.
13707
13708
    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
13709
    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
13710
    @ref number_unsigned_t, or @ref number_float_t.
13711
13712
    @return pointer to the internally stored JSON value if the requested
13713
    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
13714
13715
    @complexity Constant.
13716
13717
    @liveexample{The example below shows how pointers to internal values of a
13718
    JSON value can be requested. Note that no type conversions are made and a
13719
    `nullptr` is returned if the value and the requested pointer type does not
13720
    match.,get__PointerType}
13721
13722
    @sa @ref get_ptr() for explicit pointer-member access
13723
13724
    @since version 1.0.0
13725
    */
13726
    template<typename PointerType, typename std::enable_if<
13727
                 std::is_pointer<PointerType>::value, int>::type = 0>
13728
    PointerType get() noexcept
13729
    {
13730
        // delegate the call to get_ptr
13731
        return get_ptr<PointerType>();
13732
    }
13733
13734
    /*!
13735
    @brief get a pointer value (explicit)
13736
    @copydoc get()
13737
    */
13738
    template<typename PointerType, typename std::enable_if<
13739
                 std::is_pointer<PointerType>::value, int>::type = 0>
13740
    constexpr const PointerType get() const noexcept
13741
    {
13742
        // delegate the call to get_ptr
13743
        return get_ptr<PointerType>();
13744
    }
13745
13746
    /*!
13747
    @brief get a pointer value (implicit)
13748
13749
    Implicit pointer access to the internally stored JSON value. No copies are
13750
    made.
13751
13752
    @warning Writing data to the pointee of the result yields an undefined
13753
    state.
13754
13755
    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
13756
    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
13757
    @ref number_unsigned_t, or @ref number_float_t. Enforced by a static
13758
    assertion.
13759
13760
    @return pointer to the internally stored JSON value if the requested
13761
    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
13762
13763
    @complexity Constant.
13764
13765
    @liveexample{The example below shows how pointers to internal values of a
13766
    JSON value can be requested. Note that no type conversions are made and a
13767
    `nullptr` is returned if the value and the requested pointer type does not
13768
    match.,get_ptr}
13769
13770
    @since version 1.0.0
13771
    */
13772
    template<typename PointerType, typename std::enable_if<
13773
                 std::is_pointer<PointerType>::value, int>::type = 0>
13774
    PointerType get_ptr() noexcept
13775
    {
13776
        // get the type of the PointerType (remove pointer and const)
13777
        using pointee_t = typename std::remove_const<typename
13778
                          std::remove_pointer<typename
13779
                          std::remove_const<PointerType>::type>::type>::type;
13780
        // make sure the type matches the allowed types
13781
        static_assert(
13782
            std::is_same<object_t, pointee_t>::value
13783
            or std::is_same<array_t, pointee_t>::value
13784
            or std::is_same<string_t, pointee_t>::value
13785
            or std::is_same<boolean_t, pointee_t>::value
13786
            or std::is_same<number_integer_t, pointee_t>::value
13787
            or std::is_same<number_unsigned_t, pointee_t>::value
13788
            or std::is_same<number_float_t, pointee_t>::value
13789
            , "incompatible pointer type");
13790
13791
        // delegate the call to get_impl_ptr<>()
13792
        return get_impl_ptr(static_cast<PointerType>(nullptr));
13793
    }
13794
13795
    /*!
13796
    @brief get a pointer value (implicit)
13797
    @copydoc get_ptr()
13798
    */
13799
    template<typename PointerType, typename std::enable_if<
13800
                 std::is_pointer<PointerType>::value and
13801
                 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
13802
    constexpr const PointerType get_ptr() const noexcept
3.56k
13803
    {
3.56k
13804
        // get the type of the PointerType (remove pointer and const)
3.56k
13805
        using pointee_t = typename std::remove_const<typename
3.56k
13806
                          std::remove_pointer<typename
3.56k
13807
                          std::remove_const<PointerType>::type>::type>::type;
3.56k
13808
        // make sure the type matches the allowed types
3.56k
13809
        static_assert(
3.56k
13810
            std::is_same<object_t, pointee_t>::value
3.56k
13811
            or std::is_same<array_t, pointee_t>::value
3.56k
13812
            or std::is_same<string_t, pointee_t>::value
3.56k
13813
            or std::is_same<boolean_t, pointee_t>::value
3.56k
13814
            or std::is_same<number_integer_t, pointee_t>::value
3.56k
13815
            or std::is_same<number_unsigned_t, pointee_t>::value
3.56k
13816
            or std::is_same<number_float_t, pointee_t>::value
3.56k
13817
            , "incompatible pointer type");
3.56k
13818
3.56k
13819
        // delegate the call to get_impl_ptr<>() const
3.56k
13820
        return get_impl_ptr(static_cast<PointerType>(nullptr));
3.56k
13821
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE7get_ptrIPKmLi0EEEKT_v
152
13803
    {
152
13804
        // get the type of the PointerType (remove pointer and const)
152
13805
        using pointee_t = typename std::remove_const<typename
152
13806
                          std::remove_pointer<typename
152
13807
                          std::remove_const<PointerType>::type>::type>::type;
152
13808
        // make sure the type matches the allowed types
152
13809
        static_assert(
152
13810
            std::is_same<object_t, pointee_t>::value
152
13811
            or std::is_same<array_t, pointee_t>::value
152
13812
            or std::is_same<string_t, pointee_t>::value
152
13813
            or std::is_same<boolean_t, pointee_t>::value
152
13814
            or std::is_same<number_integer_t, pointee_t>::value
152
13815
            or std::is_same<number_unsigned_t, pointee_t>::value
152
13816
            or std::is_same<number_float_t, pointee_t>::value
152
13817
            , "incompatible pointer type");
152
13818
152
13819
        // delegate the call to get_impl_ptr<>() const
152
13820
        return get_impl_ptr(static_cast<PointerType>(nullptr));
152
13821
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE7get_ptrIPKbLi0EEEKT_v
2
13803
    {
2
13804
        // get the type of the PointerType (remove pointer and const)
2
13805
        using pointee_t = typename std::remove_const<typename
2
13806
                          std::remove_pointer<typename
2
13807
                          std::remove_const<PointerType>::type>::type>::type;
2
13808
        // make sure the type matches the allowed types
2
13809
        static_assert(
2
13810
            std::is_same<object_t, pointee_t>::value
2
13811
            or std::is_same<array_t, pointee_t>::value
2
13812
            or std::is_same<string_t, pointee_t>::value
2
13813
            or std::is_same<boolean_t, pointee_t>::value
2
13814
            or std::is_same<number_integer_t, pointee_t>::value
2
13815
            or std::is_same<number_unsigned_t, pointee_t>::value
2
13816
            or std::is_same<number_float_t, pointee_t>::value
2
13817
            , "incompatible pointer type");
2
13818
2
13819
        // delegate the call to get_impl_ptr<>() const
2
13820
        return get_impl_ptr(static_cast<PointerType>(nullptr));
2
13821
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE7get_ptrIPKS8_Li0EEEKT_v
3.26k
13803
    {
3.26k
13804
        // get the type of the PointerType (remove pointer and const)
3.26k
13805
        using pointee_t = typename std::remove_const<typename
3.26k
13806
                          std::remove_pointer<typename
3.26k
13807
                          std::remove_const<PointerType>::type>::type>::type;
3.26k
13808
        // make sure the type matches the allowed types
3.26k
13809
        static_assert(
3.26k
13810
            std::is_same<object_t, pointee_t>::value
3.26k
13811
            or std::is_same<array_t, pointee_t>::value
3.26k
13812
            or std::is_same<string_t, pointee_t>::value
3.26k
13813
            or std::is_same<boolean_t, pointee_t>::value
3.26k
13814
            or std::is_same<number_integer_t, pointee_t>::value
3.26k
13815
            or std::is_same<number_unsigned_t, pointee_t>::value
3.26k
13816
            or std::is_same<number_float_t, pointee_t>::value
3.26k
13817
            , "incompatible pointer type");
3.26k
13818
3.26k
13819
        // delegate the call to get_impl_ptr<>() const
3.26k
13820
        return get_impl_ptr(static_cast<PointerType>(nullptr));
3.26k
13821
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE7get_ptrIPKlLi0EEEKT_v
0
13803
    {
0
13804
        // get the type of the PointerType (remove pointer and const)
0
13805
        using pointee_t = typename std::remove_const<typename
0
13806
                          std::remove_pointer<typename
0
13807
                          std::remove_const<PointerType>::type>::type>::type;
0
13808
        // make sure the type matches the allowed types
0
13809
        static_assert(
0
13810
            std::is_same<object_t, pointee_t>::value
0
13811
            or std::is_same<array_t, pointee_t>::value
0
13812
            or std::is_same<string_t, pointee_t>::value
0
13813
            or std::is_same<boolean_t, pointee_t>::value
0
13814
            or std::is_same<number_integer_t, pointee_t>::value
0
13815
            or std::is_same<number_unsigned_t, pointee_t>::value
0
13816
            or std::is_same<number_float_t, pointee_t>::value
0
13817
            , "incompatible pointer type");
0
13818
0
13819
        // delegate the call to get_impl_ptr<>() const
0
13820
        return get_impl_ptr(static_cast<PointerType>(nullptr));
0
13821
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE7get_ptrIPKdLi0EEEKT_v
148
13803
    {
148
13804
        // get the type of the PointerType (remove pointer and const)
148
13805
        using pointee_t = typename std::remove_const<typename
148
13806
                          std::remove_pointer<typename
148
13807
                          std::remove_const<PointerType>::type>::type>::type;
148
13808
        // make sure the type matches the allowed types
148
13809
        static_assert(
148
13810
            std::is_same<object_t, pointee_t>::value
148
13811
            or std::is_same<array_t, pointee_t>::value
148
13812
            or std::is_same<string_t, pointee_t>::value
148
13813
            or std::is_same<boolean_t, pointee_t>::value
148
13814
            or std::is_same<number_integer_t, pointee_t>::value
148
13815
            or std::is_same<number_unsigned_t, pointee_t>::value
148
13816
            or std::is_same<number_float_t, pointee_t>::value
148
13817
            , "incompatible pointer type");
148
13818
148
13819
        // delegate the call to get_impl_ptr<>() const
148
13820
        return get_impl_ptr(static_cast<PointerType>(nullptr));
148
13821
    }
13822
13823
    /*!
13824
    @brief get a reference value (implicit)
13825
13826
    Implicit reference access to the internally stored JSON value. No copies
13827
    are made.
13828
13829
    @warning Writing data to the referee of the result yields an undefined
13830
    state.
13831
13832
    @tparam ReferenceType reference type; must be a reference to @ref array_t,
13833
    @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
13834
    @ref number_float_t. Enforced by static assertion.
13835
13836
    @return reference to the internally stored JSON value if the requested
13837
    reference type @a ReferenceType fits to the JSON value; throws
13838
    type_error.303 otherwise
13839
13840
    @throw type_error.303 in case passed type @a ReferenceType is incompatible
13841
    with the stored JSON value; see example below
13842
13843
    @complexity Constant.
13844
13845
    @liveexample{The example shows several calls to `get_ref()`.,get_ref}
13846
13847
    @since version 1.1.0
13848
    */
13849
    template<typename ReferenceType, typename std::enable_if<
13850
                 std::is_reference<ReferenceType>::value, int>::type = 0>
13851
    ReferenceType get_ref()
13852
    {
13853
        // delegate call to get_ref_impl
13854
        return get_ref_impl<ReferenceType>(*this);
13855
    }
13856
13857
    /*!
13858
    @brief get a reference value (implicit)
13859
    @copydoc get_ref()
13860
    */
13861
    template<typename ReferenceType, typename std::enable_if<
13862
                 std::is_reference<ReferenceType>::value and
13863
                 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
13864
    ReferenceType get_ref() const
13865
    {
13866
        // delegate call to get_ref_impl
13867
        return get_ref_impl<ReferenceType>(*this);
13868
    }
13869
13870
    /*!
13871
    @brief get a value (implicit)
13872
13873
    Implicit type conversion between the JSON value and a compatible value.
13874
    The call is realized by calling @ref get() const.
13875
13876
    @tparam ValueType non-pointer type compatible to the JSON value, for
13877
    instance `int` for JSON integer numbers, `bool` for JSON booleans, or
13878
    `std::vector` types for JSON arrays. The character type of @ref string_t
13879
    as well as an initializer list of this type is excluded to avoid
13880
    ambiguities as these types implicitly convert to `std::string`.
13881
13882
    @return copy of the JSON value, converted to type @a ValueType
13883
13884
    @throw type_error.302 in case passed type @a ValueType is incompatible
13885
    to the JSON value type (e.g., the JSON value is of type boolean, but a
13886
    string is requested); see example below
13887
13888
    @complexity Linear in the size of the JSON value.
13889
13890
    @liveexample{The example below shows several conversions from JSON values
13891
    to other types. There a few things to note: (1) Floating-point numbers can
13892
    be converted to integers\, (2) A JSON array can be converted to a standard
13893
    `std::vector<short>`\, (3) A JSON object can be converted to C++
13894
    associative containers such as `std::unordered_map<std::string\,
13895
    json>`.,operator__ValueType}
13896
13897
    @since version 1.0.0
13898
    */
13899
    template < typename ValueType, typename std::enable_if <
13900
                   not std::is_pointer<ValueType>::value and
13901
                   not std::is_same<ValueType, detail::json_ref<basic_json>>::value and
13902
                   not std::is_same<ValueType, typename string_t::value_type>::value and
13903
                   not detail::is_basic_json<ValueType>::value
13904
#ifndef _MSC_VER  // fix for issue #167 operator<< ambiguity under VS2015
13905
                   and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
13906
#if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914
13907
                   and not std::is_same<ValueType, typename std::string_view>::value
13908
#endif
13909
#endif
13910
                   , int >::type = 0 >
13911
    operator ValueType() const
13912
    {
13913
        // delegate the call to get<>() const
13914
        return get<ValueType>();
13915
    }
13916
13917
    /// @}
13918
13919
13920
    ////////////////////
13921
    // element access //
13922
    ////////////////////
13923
13924
    /// @name element access
13925
    /// Access to the JSON value.
13926
    /// @{
13927
13928
    /*!
13929
    @brief access specified array element with bounds checking
13930
13931
    Returns a reference to the element at specified location @a idx, with
13932
    bounds checking.
13933
13934
    @param[in] idx  index of the element to access
13935
13936
    @return reference to the element at index @a idx
13937
13938
    @throw type_error.304 if the JSON value is not an array; in this case,
13939
    calling `at` with an index makes no sense. See example below.
13940
    @throw out_of_range.401 if the index @a idx is out of range of the array;
13941
    that is, `idx >= size()`. See example below.
13942
13943
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
13944
    changes in the JSON value.
13945
13946
    @complexity Constant.
13947
13948
    @since version 1.0.0
13949
13950
    @liveexample{The example below shows how array elements can be read and
13951
    written using `at()`. It also demonstrates the different exceptions that
13952
    can be thrown.,at__size_type}
13953
    */
13954
    reference at(size_type idx)
13955
    {
13956
        // at only works for arrays
13957
        if (JSON_LIKELY(is_array()))
13958
        {
13959
            JSON_TRY
13960
            {
13961
                return m_value.array->at(idx);
13962
            }
13963
            JSON_CATCH (std::out_of_range&)
13964
            {
13965
                // create better exception explanation
13966
                JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
13967
            }
13968
        }
13969
        else
13970
        {
13971
            JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
13972
        }
13973
    }
13974
13975
    /*!
13976
    @brief access specified array element with bounds checking
13977
13978
    Returns a const reference to the element at specified location @a idx,
13979
    with bounds checking.
13980
13981
    @param[in] idx  index of the element to access
13982
13983
    @return const reference to the element at index @a idx
13984
13985
    @throw type_error.304 if the JSON value is not an array; in this case,
13986
    calling `at` with an index makes no sense. See example below.
13987
    @throw out_of_range.401 if the index @a idx is out of range of the array;
13988
    that is, `idx >= size()`. See example below.
13989
13990
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
13991
    changes in the JSON value.
13992
13993
    @complexity Constant.
13994
13995
    @since version 1.0.0
13996
13997
    @liveexample{The example below shows how array elements can be read using
13998
    `at()`. It also demonstrates the different exceptions that can be thrown.,
13999
    at__size_type_const}
14000
    */
14001
    const_reference at(size_type idx) const
14002
    {
14003
        // at only works for arrays
14004
        if (JSON_LIKELY(is_array()))
14005
        {
14006
            JSON_TRY
14007
            {
14008
                return m_value.array->at(idx);
14009
            }
14010
            JSON_CATCH (std::out_of_range&)
14011
            {
14012
                // create better exception explanation
14013
                JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
14014
            }
14015
        }
14016
        else
14017
        {
14018
            JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
14019
        }
14020
    }
14021
14022
    /*!
14023
    @brief access specified object element with bounds checking
14024
14025
    Returns a reference to the element at with specified key @a key, with
14026
    bounds checking.
14027
14028
    @param[in] key  key of the element to access
14029
14030
    @return reference to the element at key @a key
14031
14032
    @throw type_error.304 if the JSON value is not an object; in this case,
14033
    calling `at` with a key makes no sense. See example below.
14034
    @throw out_of_range.403 if the key @a key is is not stored in the object;
14035
    that is, `find(key) == end()`. See example below.
14036
14037
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
14038
    changes in the JSON value.
14039
14040
    @complexity Logarithmic in the size of the container.
14041
14042
    @sa @ref operator[](const typename object_t::key_type&) for unchecked
14043
    access by reference
14044
    @sa @ref value() for access by value with a default value
14045
14046
    @since version 1.0.0
14047
14048
    @liveexample{The example below shows how object elements can be read and
14049
    written using `at()`. It also demonstrates the different exceptions that
14050
    can be thrown.,at__object_t_key_type}
14051
    */
14052
    reference at(const typename object_t::key_type& key)
4.04k
14053
    {
4.04k
14054
        // at only works for objects
4.04k
14055
        if (JSON_LIKELY(is_object()))
4.04k
14056
        {
4.04k
14057
            JSON_TRY
4.04k
14058
            {
4.04k
14059
                return m_value.object->at(key);
4.04k
14060
            }
4.04k
14061
            JSON_CATCH (std::out_of_range&)
1
14062
            {
1
14063
                // create better exception explanation
1
14064
                JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
1
14065
            }
4.04k
14066
        }
4.04k
14067
        else
0
14068
        {
0
14069
            JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
0
14070
        }
4.04k
14071
    }
14072
14073
    /*!
14074
    @brief access specified object element with bounds checking
14075
14076
    Returns a const reference to the element at with specified key @a key,
14077
    with bounds checking.
14078
14079
    @param[in] key  key of the element to access
14080
14081
    @return const reference to the element at key @a key
14082
14083
    @throw type_error.304 if the JSON value is not an object; in this case,
14084
    calling `at` with a key makes no sense. See example below.
14085
    @throw out_of_range.403 if the key @a key is is not stored in the object;
14086
    that is, `find(key) == end()`. See example below.
14087
14088
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
14089
    changes in the JSON value.
14090
14091
    @complexity Logarithmic in the size of the container.
14092
14093
    @sa @ref operator[](const typename object_t::key_type&) for unchecked
14094
    access by reference
14095
    @sa @ref value() for access by value with a default value
14096
14097
    @since version 1.0.0
14098
14099
    @liveexample{The example below shows how object elements can be read using
14100
    `at()`. It also demonstrates the different exceptions that can be thrown.,
14101
    at__object_t_key_type_const}
14102
    */
14103
    const_reference at(const typename object_t::key_type& key) const
14104
    {
14105
        // at only works for objects
14106
        if (JSON_LIKELY(is_object()))
14107
        {
14108
            JSON_TRY
14109
            {
14110
                return m_value.object->at(key);
14111
            }
14112
            JSON_CATCH (std::out_of_range&)
14113
            {
14114
                // create better exception explanation
14115
                JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
14116
            }
14117
        }
14118
        else
14119
        {
14120
            JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
14121
        }
14122
    }
14123
14124
    /*!
14125
    @brief access specified array element
14126
14127
    Returns a reference to the element at specified location @a idx.
14128
14129
    @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
14130
    then the array is silently filled up with `null` values to make `idx` a
14131
    valid reference to the last stored element.
14132
14133
    @param[in] idx  index of the element to access
14134
14135
    @return reference to the element at index @a idx
14136
14137
    @throw type_error.305 if the JSON value is not an array or null; in that
14138
    cases, using the [] operator with an index makes no sense.
14139
14140
    @complexity Constant if @a idx is in the range of the array. Otherwise
14141
    linear in `idx - size()`.
14142
14143
    @liveexample{The example below shows how array elements can be read and
14144
    written using `[]` operator. Note the addition of `null`
14145
    values.,operatorarray__size_type}
14146
14147
    @since version 1.0.0
14148
    */
14149
    reference operator[](size_type idx)
14150
    {
14151
        // implicitly convert null value to an empty array
14152
        if (is_null())
14153
        {
14154
            m_type = value_t::array;
14155
            m_value.array = create<array_t>();
14156
            assert_invariant();
14157
        }
14158
14159
        // operator[] only works for arrays
14160
        if (JSON_LIKELY(is_array()))
14161
        {
14162
            // fill up array with null values if given idx is outside range
14163
            if (idx >= m_value.array->size())
14164
            {
14165
                m_value.array->insert(m_value.array->end(),
14166
                                      idx - m_value.array->size() + 1,
14167
                                      basic_json());
14168
            }
14169
14170
            return m_value.array->operator[](idx);
14171
        }
14172
14173
        JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name())));
14174
    }
14175
14176
    /*!
14177
    @brief access specified array element
14178
14179
    Returns a const reference to the element at specified location @a idx.
14180
14181
    @param[in] idx  index of the element to access
14182
14183
    @return const reference to the element at index @a idx
14184
14185
    @throw type_error.305 if the JSON value is not an array; in that case,
14186
    using the [] operator with an index makes no sense.
14187
14188
    @complexity Constant.
14189
14190
    @liveexample{The example below shows how array elements can be read using
14191
    the `[]` operator.,operatorarray__size_type_const}
14192
14193
    @since version 1.0.0
14194
    */
14195
    const_reference operator[](size_type idx) const
14196
    {
14197
        // const operator[] only works for arrays
14198
        if (JSON_LIKELY(is_array()))
14199
        {
14200
            return m_value.array->operator[](idx);
14201
        }
14202
14203
        JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name())));
14204
    }
14205
14206
    /*!
14207
    @brief access specified object element
14208
14209
    Returns a reference to the element at with specified key @a key.
14210
14211
    @note If @a key is not found in the object, then it is silently added to
14212
    the object and filled with a `null` value to make `key` a valid reference.
14213
    In case the value was `null` before, it is converted to an object.
14214
14215
    @param[in] key  key of the element to access
14216
14217
    @return reference to the element at key @a key
14218
14219
    @throw type_error.305 if the JSON value is not an object or null; in that
14220
    cases, using the [] operator with a key makes no sense.
14221
14222
    @complexity Logarithmic in the size of the container.
14223
14224
    @liveexample{The example below shows how object elements can be read and
14225
    written using the `[]` operator.,operatorarray__key_type}
14226
14227
    @sa @ref at(const typename object_t::key_type&) for access by reference
14228
    with range checking
14229
    @sa @ref value() for access by value with a default value
14230
14231
    @since version 1.0.0
14232
    */
14233
    reference operator[](const typename object_t::key_type& key)
122
14234
    {
122
14235
        // implicitly convert null value to an empty object
122
14236
        if (is_null())
34
14237
        {
34
14238
            m_type = value_t::object;
34
14239
            m_value.object = create<object_t>();
34
14240
            assert_invariant();
34
14241
        }
122
14242
122
14243
        // operator[] only works for objects
122
14244
        if (JSON_LIKELY(is_object()))
122
14245
        {
122
14246
            return m_value.object->operator[](key);
122
14247
        }
122
14248
0
14249
        JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
122
14250
    }
14251
14252
    /*!
14253
    @brief read-only access specified object element
14254
14255
    Returns a const reference to the element at with specified key @a key. No
14256
    bounds checking is performed.
14257
14258
    @warning If the element with key @a key does not exist, the behavior is
14259
    undefined.
14260
14261
    @param[in] key  key of the element to access
14262
14263
    @return const reference to the element at key @a key
14264
14265
    @pre The element with key @a key must exist. **This precondition is
14266
         enforced with an assertion.**
14267
14268
    @throw type_error.305 if the JSON value is not an object; in that case,
14269
    using the [] operator with a key makes no sense.
14270
14271
    @complexity Logarithmic in the size of the container.
14272
14273
    @liveexample{The example below shows how object elements can be read using
14274
    the `[]` operator.,operatorarray__key_type_const}
14275
14276
    @sa @ref at(const typename object_t::key_type&) for access by reference
14277
    with range checking
14278
    @sa @ref value() for access by value with a default value
14279
14280
    @since version 1.0.0
14281
    */
14282
    const_reference operator[](const typename object_t::key_type& key) const
14283
    {
14284
        // const operator[] only works for objects
14285
        if (JSON_LIKELY(is_object()))
14286
        {
14287
            assert(m_value.object->find(key) != m_value.object->end());
14288
            return m_value.object->find(key)->second;
14289
        }
14290
14291
        JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
14292
    }
14293
14294
    /*!
14295
    @brief access specified object element
14296
14297
    Returns a reference to the element at with specified key @a key.
14298
14299
    @note If @a key is not found in the object, then it is silently added to
14300
    the object and filled with a `null` value to make `key` a valid reference.
14301
    In case the value was `null` before, it is converted to an object.
14302
14303
    @param[in] key  key of the element to access
14304
14305
    @return reference to the element at key @a key
14306
14307
    @throw type_error.305 if the JSON value is not an object or null; in that
14308
    cases, using the [] operator with a key makes no sense.
14309
14310
    @complexity Logarithmic in the size of the container.
14311
14312
    @liveexample{The example below shows how object elements can be read and
14313
    written using the `[]` operator.,operatorarray__key_type}
14314
14315
    @sa @ref at(const typename object_t::key_type&) for access by reference
14316
    with range checking
14317
    @sa @ref value() for access by value with a default value
14318
14319
    @since version 1.1.0
14320
    */
14321
    template<typename T>
14322
    reference operator[](T* key)
636
14323
    {
636
14324
        // implicitly convert null to object
636
14325
        if (is_null())
112
14326
        {
112
14327
            m_type = value_t::object;
112
14328
            m_value = value_t::object;
112
14329
            assert_invariant();
112
14330
        }
636
14331
636
14332
        // at only works for objects
636
14333
        if (JSON_LIKELY(is_object()))
636
14334
        {
636
14335
            return m_value.object->operator[](key);
636
14336
        }
636
14337
0
14338
        JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
636
14339
    }
14340
14341
    /*!
14342
    @brief read-only access specified object element
14343
14344
    Returns a const reference to the element at with specified key @a key. No
14345
    bounds checking is performed.
14346
14347
    @warning If the element with key @a key does not exist, the behavior is
14348
    undefined.
14349
14350
    @param[in] key  key of the element to access
14351
14352
    @return const reference to the element at key @a key
14353
14354
    @pre The element with key @a key must exist. **This precondition is
14355
         enforced with an assertion.**
14356
14357
    @throw type_error.305 if the JSON value is not an object; in that case,
14358
    using the [] operator with a key makes no sense.
14359
14360
    @complexity Logarithmic in the size of the container.
14361
14362
    @liveexample{The example below shows how object elements can be read using
14363
    the `[]` operator.,operatorarray__key_type_const}
14364
14365
    @sa @ref at(const typename object_t::key_type&) for access by reference
14366
    with range checking
14367
    @sa @ref value() for access by value with a default value
14368
14369
    @since version 1.1.0
14370
    */
14371
    template<typename T>
14372
    const_reference operator[](T* key) const
14373
    {
14374
        // at only works for objects
14375
        if (JSON_LIKELY(is_object()))
14376
        {
14377
            assert(m_value.object->find(key) != m_value.object->end());
14378
            return m_value.object->find(key)->second;
14379
        }
14380
14381
        JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
14382
    }
14383
14384
    /*!
14385
    @brief access specified object element with default value
14386
14387
    Returns either a copy of an object's element at the specified key @a key
14388
    or a given default value if no element with key @a key exists.
14389
14390
    The function is basically equivalent to executing
14391
    @code {.cpp}
14392
    try {
14393
        return at(key);
14394
    } catch(out_of_range) {
14395
        return default_value;
14396
    }
14397
    @endcode
14398
14399
    @note Unlike @ref at(const typename object_t::key_type&), this function
14400
    does not throw if the given key @a key was not found.
14401
14402
    @note Unlike @ref operator[](const typename object_t::key_type& key), this
14403
    function does not implicitly add an element to the position defined by @a
14404
    key. This function is furthermore also applicable to const objects.
14405
14406
    @param[in] key  key of the element to access
14407
    @param[in] default_value  the value to return if @a key is not found
14408
14409
    @tparam ValueType type compatible to JSON values, for instance `int` for
14410
    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
14411
    JSON arrays. Note the type of the expected value at @a key and the default
14412
    value @a default_value must be compatible.
14413
14414
    @return copy of the element at key @a key or @a default_value if @a key
14415
    is not found
14416
14417
    @throw type_error.306 if the JSON value is not an object; in that case,
14418
    using `value()` with a key makes no sense.
14419
14420
    @complexity Logarithmic in the size of the container.
14421
14422
    @liveexample{The example below shows how object elements can be queried
14423
    with a default value.,basic_json__value}
14424
14425
    @sa @ref at(const typename object_t::key_type&) for access by reference
14426
    with range checking
14427
    @sa @ref operator[](const typename object_t::key_type&) for unchecked
14428
    access by reference
14429
14430
    @since version 1.0.0
14431
    */
14432
    template<class ValueType, typename std::enable_if<
14433
                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
14434
    ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
14435
    {
14436
        // at only works for objects
14437
        if (JSON_LIKELY(is_object()))
14438
        {
14439
            // if key is found, return value and given default value otherwise
14440
            const auto it = find(key);
14441
            if (it != end())
14442
            {
14443
                return *it;
14444
            }
14445
14446
            return default_value;
14447
        }
14448
14449
        JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name())));
14450
    }
14451
14452
    /*!
14453
    @brief overload for a default value of type const char*
14454
    @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const
14455
    */
14456
    string_t value(const typename object_t::key_type& key, const char* default_value) const
14457
    {
14458
        return value(key, string_t(default_value));
14459
    }
14460
14461
    /*!
14462
    @brief access specified object element via JSON Pointer with default value
14463
14464
    Returns either a copy of an object's element at the specified key @a key
14465
    or a given default value if no element with key @a key exists.
14466
14467
    The function is basically equivalent to executing
14468
    @code {.cpp}
14469
    try {
14470
        return at(ptr);
14471
    } catch(out_of_range) {
14472
        return default_value;
14473
    }
14474
    @endcode
14475
14476
    @note Unlike @ref at(const json_pointer&), this function does not throw
14477
    if the given key @a key was not found.
14478
14479
    @param[in] ptr  a JSON pointer to the element to access
14480
    @param[in] default_value  the value to return if @a ptr found no value
14481
14482
    @tparam ValueType type compatible to JSON values, for instance `int` for
14483
    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
14484
    JSON arrays. Note the type of the expected value at @a key and the default
14485
    value @a default_value must be compatible.
14486
14487
    @return copy of the element at key @a key or @a default_value if @a key
14488
    is not found
14489
14490
    @throw type_error.306 if the JSON value is not an object; in that case,
14491
    using `value()` with a key makes no sense.
14492
14493
    @complexity Logarithmic in the size of the container.
14494
14495
    @liveexample{The example below shows how object elements can be queried
14496
    with a default value.,basic_json__value_ptr}
14497
14498
    @sa @ref operator[](const json_pointer&) for unchecked access by reference
14499
14500
    @since version 2.0.2
14501
    */
14502
    template<class ValueType, typename std::enable_if<
14503
                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
14504
    ValueType value(const json_pointer& ptr, const ValueType& default_value) const
14505
    {
14506
        // at only works for objects
14507
        if (JSON_LIKELY(is_object()))
14508
        {
14509
            // if pointer resolves a value, return it or use default value
14510
            JSON_TRY
14511
            {
14512
                return ptr.get_checked(this);
14513
            }
14514
            JSON_INTERNAL_CATCH (out_of_range&)
14515
            {
14516
                return default_value;
14517
            }
14518
        }
14519
14520
        JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name())));
14521
    }
14522
14523
    /*!
14524
    @brief overload for a default value of type const char*
14525
    @copydoc basic_json::value(const json_pointer&, ValueType) const
14526
    */
14527
    string_t value(const json_pointer& ptr, const char* default_value) const
14528
    {
14529
        return value(ptr, string_t(default_value));
14530
    }
14531
14532
    /*!
14533
    @brief access the first element
14534
14535
    Returns a reference to the first element in the container. For a JSON
14536
    container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
14537
14538
    @return In case of a structured type (array or object), a reference to the
14539
    first element is returned. In case of number, string, or boolean values, a
14540
    reference to the value is returned.
14541
14542
    @complexity Constant.
14543
14544
    @pre The JSON value must not be `null` (would throw `std::out_of_range`)
14545
    or an empty array or object (undefined behavior, **guarded by
14546
    assertions**).
14547
    @post The JSON value remains unchanged.
14548
14549
    @throw invalid_iterator.214 when called on `null` value
14550
14551
    @liveexample{The following code shows an example for `front()`.,front}
14552
14553
    @sa @ref back() -- access the last element
14554
14555
    @since version 1.0.0
14556
    */
14557
    reference front()
14558
    {
14559
        return *begin();
14560
    }
14561
14562
    /*!
14563
    @copydoc basic_json::front()
14564
    */
14565
    const_reference front() const
14566
    {
14567
        return *cbegin();
14568
    }
14569
14570
    /*!
14571
    @brief access the last element
14572
14573
    Returns a reference to the last element in the container. For a JSON
14574
    container `c`, the expression `c.back()` is equivalent to
14575
    @code {.cpp}
14576
    auto tmp = c.end();
14577
    --tmp;
14578
    return *tmp;
14579
    @endcode
14580
14581
    @return In case of a structured type (array or object), a reference to the
14582
    last element is returned. In case of number, string, or boolean values, a
14583
    reference to the value is returned.
14584
14585
    @complexity Constant.
14586
14587
    @pre The JSON value must not be `null` (would throw `std::out_of_range`)
14588
    or an empty array or object (undefined behavior, **guarded by
14589
    assertions**).
14590
    @post The JSON value remains unchanged.
14591
14592
    @throw invalid_iterator.214 when called on a `null` value. See example
14593
    below.
14594
14595
    @liveexample{The following code shows an example for `back()`.,back}
14596
14597
    @sa @ref front() -- access the first element
14598
14599
    @since version 1.0.0
14600
    */
14601
    reference back()
14602
    {
14603
        auto tmp = end();
14604
        --tmp;
14605
        return *tmp;
14606
    }
14607
14608
    /*!
14609
    @copydoc basic_json::back()
14610
    */
14611
    const_reference back() const
14612
    {
14613
        auto tmp = cend();
14614
        --tmp;
14615
        return *tmp;
14616
    }
14617
14618
    /*!
14619
    @brief remove element given an iterator
14620
14621
    Removes the element specified by iterator @a pos. The iterator @a pos must
14622
    be valid and dereferenceable. Thus the `end()` iterator (which is valid,
14623
    but is not dereferenceable) cannot be used as a value for @a pos.
14624
14625
    If called on a primitive type other than `null`, the resulting JSON value
14626
    will be `null`.
14627
14628
    @param[in] pos iterator to the element to remove
14629
    @return Iterator following the last removed element. If the iterator @a
14630
    pos refers to the last element, the `end()` iterator is returned.
14631
14632
    @tparam IteratorType an @ref iterator or @ref const_iterator
14633
14634
    @post Invalidates iterators and references at or after the point of the
14635
    erase, including the `end()` iterator.
14636
14637
    @throw type_error.307 if called on a `null` value; example: `"cannot use
14638
    erase() with null"`
14639
    @throw invalid_iterator.202 if called on an iterator which does not belong
14640
    to the current JSON value; example: `"iterator does not fit current
14641
    value"`
14642
    @throw invalid_iterator.205 if called on a primitive type with invalid
14643
    iterator (i.e., any iterator which is not `begin()`); example: `"iterator
14644
    out of range"`
14645
14646
    @complexity The complexity depends on the type:
14647
    - objects: amortized constant
14648
    - arrays: linear in distance between @a pos and the end of the container
14649
    - strings: linear in the length of the string
14650
    - other types: constant
14651
14652
    @liveexample{The example shows the result of `erase()` for different JSON
14653
    types.,erase__IteratorType}
14654
14655
    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
14656
    the given range
14657
    @sa @ref erase(const typename object_t::key_type&) -- removes the element
14658
    from an object at the given key
14659
    @sa @ref erase(const size_type) -- removes the element from an array at
14660
    the given index
14661
14662
    @since version 1.0.0
14663
    */
14664
    template<class IteratorType, typename std::enable_if<
14665
                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
14666
                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
14667
             = 0>
14668
    IteratorType erase(IteratorType pos)
0
14669
    {
0
14670
        // make sure iterator fits the current value
0
14671
        if (JSON_UNLIKELY(this != pos.m_object))
0
14672
        {
0
14673
            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
0
14674
        }
0
14675
0
14676
        IteratorType result = end();
0
14677
0
14678
        switch (m_type)
0
14679
        {
0
14680
            case value_t::boolean:
0
14681
            case value_t::number_float:
0
14682
            case value_t::number_integer:
0
14683
            case value_t::number_unsigned:
0
14684
            case value_t::string:
0
14685
            {
0
14686
                if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin()))
0
14687
                {
0
14688
                    JSON_THROW(invalid_iterator::create(205, "iterator out of range"));
0
14689
                }
0
14690
0
14691
                if (is_string())
0
14692
                {
0
14693
                    AllocatorType<string_t> alloc;
0
14694
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
0
14695
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
0
14696
                    m_value.string = nullptr;
0
14697
                }
0
14698
0
14699
                m_type = value_t::null;
0
14700
                assert_invariant();
0
14701
                break;
0
14702
            }
0
14703
0
14704
            case value_t::object:
0
14705
            {
0
14706
                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
0
14707
                break;
0
14708
            }
0
14709
0
14710
            case value_t::array:
0
14711
            {
0
14712
                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
0
14713
                break;
0
14714
            }
0
14715
0
14716
            default:
0
14717
                JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
0
14718
        }
0
14719
0
14720
        return result;
0
14721
    }
14722
14723
    /*!
14724
    @brief remove elements given an iterator range
14725
14726
    Removes the element specified by the range `[first; last)`. The iterator
14727
    @a first does not need to be dereferenceable if `first == last`: erasing
14728
    an empty range is a no-op.
14729
14730
    If called on a primitive type other than `null`, the resulting JSON value
14731
    will be `null`.
14732
14733
    @param[in] first iterator to the beginning of the range to remove
14734
    @param[in] last iterator past the end of the range to remove
14735
    @return Iterator following the last removed element. If the iterator @a
14736
    second refers to the last element, the `end()` iterator is returned.
14737
14738
    @tparam IteratorType an @ref iterator or @ref const_iterator
14739
14740
    @post Invalidates iterators and references at or after the point of the
14741
    erase, including the `end()` iterator.
14742
14743
    @throw type_error.307 if called on a `null` value; example: `"cannot use
14744
    erase() with null"`
14745
    @throw invalid_iterator.203 if called on iterators which does not belong
14746
    to the current JSON value; example: `"iterators do not fit current value"`
14747
    @throw invalid_iterator.204 if called on a primitive type with invalid
14748
    iterators (i.e., if `first != begin()` and `last != end()`); example:
14749
    `"iterators out of range"`
14750
14751
    @complexity The complexity depends on the type:
14752
    - objects: `log(size()) + std::distance(first, last)`
14753
    - arrays: linear in the distance between @a first and @a last, plus linear
14754
      in the distance between @a last and end of the container
14755
    - strings: linear in the length of the string
14756
    - other types: constant
14757
14758
    @liveexample{The example shows the result of `erase()` for different JSON
14759
    types.,erase__IteratorType_IteratorType}
14760
14761
    @sa @ref erase(IteratorType) -- removes the element at a given position
14762
    @sa @ref erase(const typename object_t::key_type&) -- removes the element
14763
    from an object at the given key
14764
    @sa @ref erase(const size_type) -- removes the element from an array at
14765
    the given index
14766
14767
    @since version 1.0.0
14768
    */
14769
    template<class IteratorType, typename std::enable_if<
14770
                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
14771
                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
14772
             = 0>
14773
    IteratorType erase(IteratorType first, IteratorType last)
14774
    {
14775
        // make sure iterator fits the current value
14776
        if (JSON_UNLIKELY(this != first.m_object or this != last.m_object))
14777
        {
14778
            JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value"));
14779
        }
14780
14781
        IteratorType result = end();
14782
14783
        switch (m_type)
14784
        {
14785
            case value_t::boolean:
14786
            case value_t::number_float:
14787
            case value_t::number_integer:
14788
            case value_t::number_unsigned:
14789
            case value_t::string:
14790
            {
14791
                if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin()
14792
                                or not last.m_it.primitive_iterator.is_end()))
14793
                {
14794
                    JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
14795
                }
14796
14797
                if (is_string())
14798
                {
14799
                    AllocatorType<string_t> alloc;
14800
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
14801
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
14802
                    m_value.string = nullptr;
14803
                }
14804
14805
                m_type = value_t::null;
14806
                assert_invariant();
14807
                break;
14808
            }
14809
14810
            case value_t::object:
14811
            {
14812
                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
14813
                                              last.m_it.object_iterator);
14814
                break;
14815
            }
14816
14817
            case value_t::array:
14818
            {
14819
                result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
14820
                                             last.m_it.array_iterator);
14821
                break;
14822
            }
14823
14824
            default:
14825
                JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
14826
        }
14827
14828
        return result;
14829
    }
14830
14831
    /*!
14832
    @brief remove element from a JSON object given a key
14833
14834
    Removes elements from a JSON object with the key value @a key.
14835
14836
    @param[in] key value of the elements to remove
14837
14838
    @return Number of elements removed. If @a ObjectType is the default
14839
    `std::map` type, the return value will always be `0` (@a key was not
14840
    found) or `1` (@a key was found).
14841
14842
    @post References and iterators to the erased elements are invalidated.
14843
    Other references and iterators are not affected.
14844
14845
    @throw type_error.307 when called on a type other than JSON object;
14846
    example: `"cannot use erase() with null"`
14847
14848
    @complexity `log(size()) + count(key)`
14849
14850
    @liveexample{The example shows the effect of `erase()`.,erase__key_type}
14851
14852
    @sa @ref erase(IteratorType) -- removes the element at a given position
14853
    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
14854
    the given range
14855
    @sa @ref erase(const size_type) -- removes the element from an array at
14856
    the given index
14857
14858
    @since version 1.0.0
14859
    */
14860
    size_type erase(const typename object_t::key_type& key)
14861
    {
14862
        // this erase only works for objects
14863
        if (JSON_LIKELY(is_object()))
14864
        {
14865
            return m_value.object->erase(key);
14866
        }
14867
14868
        JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
14869
    }
14870
14871
    /*!
14872
    @brief remove element from a JSON array given an index
14873
14874
    Removes element from a JSON array at the index @a idx.
14875
14876
    @param[in] idx index of the element to remove
14877
14878
    @throw type_error.307 when called on a type other than JSON object;
14879
    example: `"cannot use erase() with null"`
14880
    @throw out_of_range.401 when `idx >= size()`; example: `"array index 17
14881
    is out of range"`
14882
14883
    @complexity Linear in distance between @a idx and the end of the container.
14884
14885
    @liveexample{The example shows the effect of `erase()`.,erase__size_type}
14886
14887
    @sa @ref erase(IteratorType) -- removes the element at a given position
14888
    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
14889
    the given range
14890
    @sa @ref erase(const typename object_t::key_type&) -- removes the element
14891
    from an object at the given key
14892
14893
    @since version 1.0.0
14894
    */
14895
    void erase(const size_type idx)
14896
    {
14897
        // this erase only works for arrays
14898
        if (JSON_LIKELY(is_array()))
14899
        {
14900
            if (JSON_UNLIKELY(idx >= size()))
14901
            {
14902
                JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
14903
            }
14904
14905
            m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
14906
        }
14907
        else
14908
        {
14909
            JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
14910
        }
14911
    }
14912
14913
    /// @}
14914
14915
14916
    ////////////
14917
    // lookup //
14918
    ////////////
14919
14920
    /// @name lookup
14921
    /// @{
14922
14923
    /*!
14924
    @brief find an element in a JSON object
14925
14926
    Finds an element in a JSON object with key equivalent to @a key. If the
14927
    element is not found or the JSON value is not an object, end() is
14928
    returned.
14929
14930
    @note This method always returns @ref end() when executed on a JSON type
14931
          that is not an object.
14932
14933
    @param[in] key key value of the element to search for.
14934
14935
    @return Iterator to an element with key equivalent to @a key. If no such
14936
    element is found or the JSON value is not an object, past-the-end (see
14937
    @ref end()) iterator is returned.
14938
14939
    @complexity Logarithmic in the size of the JSON object.
14940
14941
    @liveexample{The example shows how `find()` is used.,find__key_type}
14942
14943
    @since version 1.0.0
14944
    */
14945
    template<typename KeyT>
14946
    iterator find(KeyT&& key)
15
14947
    {
15
14948
        auto result = end();
15
14949
15
14950
        if (is_object())
14
14951
        {
14
14952
            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));
14
14953
        }
15
14954
15
14955
        return result;
15
14956
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE4findIRA9_KcEENS_6detail9iter_implISA_EEOT_
13
14947
    {
13
14948
        auto result = end();
13
14949
13
14950
        if (is_object())
12
14951
        {
12
14952
            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));
12
14953
        }
13
14954
13
14955
        return result;
13
14956
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE4findIRA15_KcEENS_6detail9iter_implISA_EEOT_
2
14947
    {
2
14948
        auto result = end();
2
14949
2
14950
        if (is_object())
2
14951
        {
2
14952
            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));
2
14953
        }
2
14954
2
14955
        return result;
2
14956
    }
14957
14958
    /*!
14959
    @brief find an element in a JSON object
14960
    @copydoc find(KeyT&&)
14961
    */
14962
    template<typename KeyT>
14963
    const_iterator find(KeyT&& key) const
14964
    {
14965
        auto result = cend();
14966
14967
        if (is_object())
14968
        {
14969
            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));
14970
        }
14971
14972
        return result;
14973
    }
14974
14975
    /*!
14976
    @brief returns the number of occurrences of a key in a JSON object
14977
14978
    Returns the number of elements with key @a key. If ObjectType is the
14979
    default `std::map` type, the return value will always be `0` (@a key was
14980
    not found) or `1` (@a key was found).
14981
14982
    @note This method always returns `0` when executed on a JSON type that is
14983
          not an object.
14984
14985
    @param[in] key key value of the element to count
14986
14987
    @return Number of elements with key @a key. If the JSON value is not an
14988
    object, the return value will be `0`.
14989
14990
    @complexity Logarithmic in the size of the JSON object.
14991
14992
    @liveexample{The example shows how `count()` is used.,count}
14993
14994
    @since version 1.0.0
14995
    */
14996
    template<typename KeyT>
14997
    size_type count(KeyT&& key) const
14998
    {
14999
        // return 0 for all nonobject types
15000
        return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0;
15001
    }
15002
15003
    /// @}
15004
15005
15006
    ///////////////
15007
    // iterators //
15008
    ///////////////
15009
15010
    /// @name iterators
15011
    /// @{
15012
15013
    /*!
15014
    @brief returns an iterator to the first element
15015
15016
    Returns an iterator to the first element.
15017
15018
    @image html range-begin-end.svg "Illustration from cppreference.com"
15019
15020
    @return iterator to the first element
15021
15022
    @complexity Constant.
15023
15024
    @requirement This function helps `basic_json` satisfying the
15025
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15026
    requirements:
15027
    - The complexity is constant.
15028
15029
    @liveexample{The following code shows an example for `begin()`.,begin}
15030
15031
    @sa @ref cbegin() -- returns a const iterator to the beginning
15032
    @sa @ref end() -- returns an iterator to the end
15033
    @sa @ref cend() -- returns a const iterator to the end
15034
15035
    @since version 1.0.0
15036
    */
15037
    iterator begin() noexcept
170
15038
    {
170
15039
        iterator result(this);
170
15040
        result.set_begin();
170
15041
        return result;
170
15042
    }
15043
15044
    /*!
15045
    @copydoc basic_json::cbegin()
15046
    */
15047
    const_iterator begin() const noexcept
15048
    {
15049
        return cbegin();
15050
    }
15051
15052
    /*!
15053
    @brief returns a const iterator to the first element
15054
15055
    Returns a const iterator to the first element.
15056
15057
    @image html range-begin-end.svg "Illustration from cppreference.com"
15058
15059
    @return const iterator to the first element
15060
15061
    @complexity Constant.
15062
15063
    @requirement This function helps `basic_json` satisfying the
15064
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15065
    requirements:
15066
    - The complexity is constant.
15067
    - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.
15068
15069
    @liveexample{The following code shows an example for `cbegin()`.,cbegin}
15070
15071
    @sa @ref begin() -- returns an iterator to the beginning
15072
    @sa @ref end() -- returns an iterator to the end
15073
    @sa @ref cend() -- returns a const iterator to the end
15074
15075
    @since version 1.0.0
15076
    */
15077
    const_iterator cbegin() const noexcept
15078
    {
15079
        const_iterator result(this);
15080
        result.set_begin();
15081
        return result;
15082
    }
15083
15084
    /*!
15085
    @brief returns an iterator to one past the last element
15086
15087
    Returns an iterator to one past the last element.
15088
15089
    @image html range-begin-end.svg "Illustration from cppreference.com"
15090
15091
    @return iterator one past the last element
15092
15093
    @complexity Constant.
15094
15095
    @requirement This function helps `basic_json` satisfying the
15096
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15097
    requirements:
15098
    - The complexity is constant.
15099
15100
    @liveexample{The following code shows an example for `end()`.,end}
15101
15102
    @sa @ref cend() -- returns a const iterator to the end
15103
    @sa @ref begin() -- returns an iterator to the beginning
15104
    @sa @ref cbegin() -- returns a const iterator to the beginning
15105
15106
    @since version 1.0.0
15107
    */
15108
    iterator end() noexcept
580
15109
    {
580
15110
        iterator result(this);
580
15111
        result.set_end();
580
15112
        return result;
580
15113
    }
15114
15115
    /*!
15116
    @copydoc basic_json::cend()
15117
    */
15118
    const_iterator end() const noexcept
15119
    {
15120
        return cend();
15121
    }
15122
15123
    /*!
15124
    @brief returns a const iterator to one past the last element
15125
15126
    Returns a const iterator to one past the last element.
15127
15128
    @image html range-begin-end.svg "Illustration from cppreference.com"
15129
15130
    @return const iterator one past the last element
15131
15132
    @complexity Constant.
15133
15134
    @requirement This function helps `basic_json` satisfying the
15135
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15136
    requirements:
15137
    - The complexity is constant.
15138
    - Has the semantics of `const_cast<const basic_json&>(*this).end()`.
15139
15140
    @liveexample{The following code shows an example for `cend()`.,cend}
15141
15142
    @sa @ref end() -- returns an iterator to the end
15143
    @sa @ref begin() -- returns an iterator to the beginning
15144
    @sa @ref cbegin() -- returns a const iterator to the beginning
15145
15146
    @since version 1.0.0
15147
    */
15148
    const_iterator cend() const noexcept
15149
    {
15150
        const_iterator result(this);
15151
        result.set_end();
15152
        return result;
15153
    }
15154
15155
    /*!
15156
    @brief returns an iterator to the reverse-beginning
15157
15158
    Returns an iterator to the reverse-beginning; that is, the last element.
15159
15160
    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
15161
15162
    @complexity Constant.
15163
15164
    @requirement This function helps `basic_json` satisfying the
15165
    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
15166
    requirements:
15167
    - The complexity is constant.
15168
    - Has the semantics of `reverse_iterator(end())`.
15169
15170
    @liveexample{The following code shows an example for `rbegin()`.,rbegin}
15171
15172
    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
15173
    @sa @ref rend() -- returns a reverse iterator to the end
15174
    @sa @ref crend() -- returns a const reverse iterator to the end
15175
15176
    @since version 1.0.0
15177
    */
15178
    reverse_iterator rbegin() noexcept
15179
    {
15180
        return reverse_iterator(end());
15181
    }
15182
15183
    /*!
15184
    @copydoc basic_json::crbegin()
15185
    */
15186
    const_reverse_iterator rbegin() const noexcept
15187
    {
15188
        return crbegin();
15189
    }
15190
15191
    /*!
15192
    @brief returns an iterator to the reverse-end
15193
15194
    Returns an iterator to the reverse-end; that is, one before the first
15195
    element.
15196
15197
    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
15198
15199
    @complexity Constant.
15200
15201
    @requirement This function helps `basic_json` satisfying the
15202
    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
15203
    requirements:
15204
    - The complexity is constant.
15205
    - Has the semantics of `reverse_iterator(begin())`.
15206
15207
    @liveexample{The following code shows an example for `rend()`.,rend}
15208
15209
    @sa @ref crend() -- returns a const reverse iterator to the end
15210
    @sa @ref rbegin() -- returns a reverse iterator to the beginning
15211
    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
15212
15213
    @since version 1.0.0
15214
    */
15215
    reverse_iterator rend() noexcept
15216
    {
15217
        return reverse_iterator(begin());
15218
    }
15219
15220
    /*!
15221
    @copydoc basic_json::crend()
15222
    */
15223
    const_reverse_iterator rend() const noexcept
15224
    {
15225
        return crend();
15226
    }
15227
15228
    /*!
15229
    @brief returns a const reverse iterator to the last element
15230
15231
    Returns a const iterator to the reverse-beginning; that is, the last
15232
    element.
15233
15234
    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
15235
15236
    @complexity Constant.
15237
15238
    @requirement This function helps `basic_json` satisfying the
15239
    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
15240
    requirements:
15241
    - The complexity is constant.
15242
    - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.
15243
15244
    @liveexample{The following code shows an example for `crbegin()`.,crbegin}
15245
15246
    @sa @ref rbegin() -- returns a reverse iterator to the beginning
15247
    @sa @ref rend() -- returns a reverse iterator to the end
15248
    @sa @ref crend() -- returns a const reverse iterator to the end
15249
15250
    @since version 1.0.0
15251
    */
15252
    const_reverse_iterator crbegin() const noexcept
15253
    {
15254
        return const_reverse_iterator(cend());
15255
    }
15256
15257
    /*!
15258
    @brief returns a const reverse iterator to one before the first
15259
15260
    Returns a const reverse iterator to the reverse-end; that is, one before
15261
    the first element.
15262
15263
    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
15264
15265
    @complexity Constant.
15266
15267
    @requirement This function helps `basic_json` satisfying the
15268
    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
15269
    requirements:
15270
    - The complexity is constant.
15271
    - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.
15272
15273
    @liveexample{The following code shows an example for `crend()`.,crend}
15274
15275
    @sa @ref rend() -- returns a reverse iterator to the end
15276
    @sa @ref rbegin() -- returns a reverse iterator to the beginning
15277
    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
15278
15279
    @since version 1.0.0
15280
    */
15281
    const_reverse_iterator crend() const noexcept
15282
    {
15283
        return const_reverse_iterator(cbegin());
15284
    }
15285
15286
  public:
15287
    /*!
15288
    @brief wrapper to access iterator member functions in range-based for
15289
15290
    This function allows to access @ref iterator::key() and @ref
15291
    iterator::value() during range-based for loops. In these loops, a
15292
    reference to the JSON values is returned, so there is no access to the
15293
    underlying iterator.
15294
15295
    For loop without iterator_wrapper:
15296
15297
    @code{cpp}
15298
    for (auto it = j_object.begin(); it != j_object.end(); ++it)
15299
    {
15300
        std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
15301
    }
15302
    @endcode
15303
15304
    Range-based for loop without iterator proxy:
15305
15306
    @code{cpp}
15307
    for (auto it : j_object)
15308
    {
15309
        // "it" is of type json::reference and has no key() member
15310
        std::cout << "value: " << it << '\n';
15311
    }
15312
    @endcode
15313
15314
    Range-based for loop with iterator proxy:
15315
15316
    @code{cpp}
15317
    for (auto it : json::iterator_wrapper(j_object))
15318
    {
15319
        std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
15320
    }
15321
    @endcode
15322
15323
    @note When iterating over an array, `key()` will return the index of the
15324
          element as string (see example).
15325
15326
    @param[in] ref  reference to a JSON value
15327
    @return iteration proxy object wrapping @a ref with an interface to use in
15328
            range-based for loops
15329
15330
    @liveexample{The following code shows how the wrapper is used,iterator_wrapper}
15331
15332
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
15333
    changes in the JSON value.
15334
15335
    @complexity Constant.
15336
15337
    @note The name of this function is not yet final and may change in the
15338
    future.
15339
15340
    @deprecated This stream operator is deprecated and will be removed in
15341
                future 4.0.0 of the library. Please use @ref items() instead;
15342
                that is, replace `json::iterator_wrapper(j)` with `j.items()`.
15343
    */
15344
    JSON_DEPRECATED
15345
    static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
15346
    {
15347
        return ref.items();
15348
    }
15349
15350
    /*!
15351
    @copydoc iterator_wrapper(reference)
15352
    */
15353
    JSON_DEPRECATED
15354
    static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
15355
    {
15356
        return ref.items();
15357
    }
15358
15359
    /*!
15360
    @brief helper to access iterator member functions in range-based for
15361
15362
    This function allows to access @ref iterator::key() and @ref
15363
    iterator::value() during range-based for loops. In these loops, a
15364
    reference to the JSON values is returned, so there is no access to the
15365
    underlying iterator.
15366
15367
    For loop without `items()` function:
15368
15369
    @code{cpp}
15370
    for (auto it = j_object.begin(); it != j_object.end(); ++it)
15371
    {
15372
        std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
15373
    }
15374
    @endcode
15375
15376
    Range-based for loop without `items()` function:
15377
15378
    @code{cpp}
15379
    for (auto it : j_object)
15380
    {
15381
        // "it" is of type json::reference and has no key() member
15382
        std::cout << "value: " << it << '\n';
15383
    }
15384
    @endcode
15385
15386
    Range-based for loop with `items()` function:
15387
15388
    @code{cpp}
15389
    for (auto it : j_object.items())
15390
    {
15391
        std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
15392
    }
15393
    @endcode
15394
15395
    @note When iterating over an array, `key()` will return the index of the
15396
          element as string (see example). For primitive types (e.g., numbers),
15397
          `key()` returns an empty string.
15398
15399
    @return iteration proxy object wrapping @a ref with an interface to use in
15400
            range-based for loops
15401
15402
    @liveexample{The following code shows how the function is used.,items}
15403
15404
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
15405
    changes in the JSON value.
15406
15407
    @complexity Constant.
15408
15409
    @since version 3.1.0.
15410
    */
15411
    iteration_proxy<iterator> items() noexcept
15412
    {
15413
        return iteration_proxy<iterator>(*this);
15414
    }
15415
15416
    /*!
15417
    @copydoc items()
15418
    */
15419
    iteration_proxy<const_iterator> items() const noexcept
15420
    {
15421
        return iteration_proxy<const_iterator>(*this);
15422
    }
15423
15424
    /// @}
15425
15426
15427
    //////////////
15428
    // capacity //
15429
    //////////////
15430
15431
    /// @name capacity
15432
    /// @{
15433
15434
    /*!
15435
    @brief checks whether the container is empty.
15436
15437
    Checks if a JSON value has no elements (i.e. whether its @ref size is `0`).
15438
15439
    @return The return value depends on the different types and is
15440
            defined as follows:
15441
            Value type  | return value
15442
            ----------- | -------------
15443
            null        | `true`
15444
            boolean     | `false`
15445
            string      | `false`
15446
            number      | `false`
15447
            object      | result of function `object_t::empty()`
15448
            array       | result of function `array_t::empty()`
15449
15450
    @liveexample{The following code uses `empty()` to check if a JSON
15451
    object contains any elements.,empty}
15452
15453
    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
15454
    the Container concept; that is, their `empty()` functions have constant
15455
    complexity.
15456
15457
    @iterators No changes.
15458
15459
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
15460
15461
    @note This function does not return whether a string stored as JSON value
15462
    is empty - it returns whether the JSON container itself is empty which is
15463
    false in the case of a string.
15464
15465
    @requirement This function helps `basic_json` satisfying the
15466
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15467
    requirements:
15468
    - The complexity is constant.
15469
    - Has the semantics of `begin() == end()`.
15470
15471
    @sa @ref size() -- returns the number of elements
15472
15473
    @since version 1.0.0
15474
    */
15475
    bool empty() const noexcept
15476
    {
15477
        switch (m_type)
15478
        {
15479
            case value_t::null:
15480
            {
15481
                // null values are empty
15482
                return true;
15483
            }
15484
15485
            case value_t::array:
15486
            {
15487
                // delegate call to array_t::empty()
15488
                return m_value.array->empty();
15489
            }
15490
15491
            case value_t::object:
15492
            {
15493
                // delegate call to object_t::empty()
15494
                return m_value.object->empty();
15495
            }
15496
15497
            default:
15498
            {
15499
                // all other types are nonempty
15500
                return false;
15501
            }
15502
        }
15503
    }
15504
15505
    /*!
15506
    @brief returns the number of elements
15507
15508
    Returns the number of elements in a JSON value.
15509
15510
    @return The return value depends on the different types and is
15511
            defined as follows:
15512
            Value type  | return value
15513
            ----------- | -------------
15514
            null        | `0`
15515
            boolean     | `1`
15516
            string      | `1`
15517
            number      | `1`
15518
            object      | result of function object_t::size()
15519
            array       | result of function array_t::size()
15520
15521
    @liveexample{The following code calls `size()` on the different value
15522
    types.,size}
15523
15524
    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
15525
    the Container concept; that is, their size() functions have constant
15526
    complexity.
15527
15528
    @iterators No changes.
15529
15530
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
15531
15532
    @note This function does not return the length of a string stored as JSON
15533
    value - it returns the number of elements in the JSON value which is 1 in
15534
    the case of a string.
15535
15536
    @requirement This function helps `basic_json` satisfying the
15537
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15538
    requirements:
15539
    - The complexity is constant.
15540
    - Has the semantics of `std::distance(begin(), end())`.
15541
15542
    @sa @ref empty() -- checks whether the container is empty
15543
    @sa @ref max_size() -- returns the maximal number of elements
15544
15545
    @since version 1.0.0
15546
    */
15547
    size_type size() const noexcept
33
15548
    {
0
15549
        switch (m_type)
0
15550
        {
13
15551
            case value_t::null:
13
15552
            {
13
15553
                // null values are empty
13
15554
                return 0;
13
15555
            }
13
15556
20
15557
            case value_t::array:
20
15558
            {
20
15559
                // delegate call to array_t::size()
20
15560
                return m_value.array->size();
13
15561
            }
13
15562
0
15563
            case value_t::object:
0
15564
            {
0
15565
                // delegate call to object_t::size()
0
15566
                return m_value.object->size();
13
15567
            }
13
15568
0
15569
            default:
0
15570
            {
0
15571
                // all other types have size 1
0
15572
                return 1;
13
15573
            }
0
15574
        }
33
15575
    }
15576
15577
    /*!
15578
    @brief returns the maximum possible number of elements
15579
15580
    Returns the maximum number of elements a JSON value is able to hold due to
15581
    system or library implementation limitations, i.e. `std::distance(begin(),
15582
    end())` for the JSON value.
15583
15584
    @return The return value depends on the different types and is
15585
            defined as follows:
15586
            Value type  | return value
15587
            ----------- | -------------
15588
            null        | `0` (same as `size()`)
15589
            boolean     | `1` (same as `size()`)
15590
            string      | `1` (same as `size()`)
15591
            number      | `1` (same as `size()`)
15592
            object      | result of function `object_t::max_size()`
15593
            array       | result of function `array_t::max_size()`
15594
15595
    @liveexample{The following code calls `max_size()` on the different value
15596
    types. Note the output is implementation specific.,max_size}
15597
15598
    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
15599
    the Container concept; that is, their `max_size()` functions have constant
15600
    complexity.
15601
15602
    @iterators No changes.
15603
15604
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
15605
15606
    @requirement This function helps `basic_json` satisfying the
15607
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15608
    requirements:
15609
    - The complexity is constant.
15610
    - Has the semantics of returning `b.size()` where `b` is the largest
15611
      possible JSON value.
15612
15613
    @sa @ref size() -- returns the number of elements
15614
15615
    @since version 1.0.0
15616
    */
15617
    size_type max_size() const noexcept
0
15618
    {
0
15619
        switch (m_type)
0
15620
        {
0
15621
            case value_t::array:
0
15622
            {
0
15623
                // delegate call to array_t::max_size()
0
15624
                return m_value.array->max_size();
0
15625
            }
0
15626
0
15627
            case value_t::object:
0
15628
            {
0
15629
                // delegate call to object_t::max_size()
0
15630
                return m_value.object->max_size();
0
15631
            }
0
15632
0
15633
            default:
0
15634
            {
0
15635
                // all other types have max_size() == size()
0
15636
                return size();
0
15637
            }
0
15638
        }
0
15639
    }
15640
15641
    /// @}
15642
15643
15644
    ///////////////
15645
    // modifiers //
15646
    ///////////////
15647
15648
    /// @name modifiers
15649
    /// @{
15650
15651
    /*!
15652
    @brief clears the contents
15653
15654
    Clears the content of a JSON value and resets it to the default value as
15655
    if @ref basic_json(value_t) would have been called with the current value
15656
    type from @ref type():
15657
15658
    Value type  | initial value
15659
    ----------- | -------------
15660
    null        | `null`
15661
    boolean     | `false`
15662
    string      | `""`
15663
    number      | `0`
15664
    object      | `{}`
15665
    array       | `[]`
15666
15667
    @post Has the same effect as calling
15668
    @code {.cpp}
15669
    *this = basic_json(type());
15670
    @endcode
15671
15672
    @liveexample{The example below shows the effect of `clear()` to different
15673
    JSON types.,clear}
15674
15675
    @complexity Linear in the size of the JSON value.
15676
15677
    @iterators All iterators, pointers and references related to this container
15678
               are invalidated.
15679
15680
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
15681
15682
    @sa @ref basic_json(value_t) -- constructor that creates an object with the
15683
        same value than calling `clear()`
15684
15685
    @since version 1.0.0
15686
    */
15687
    void clear() noexcept
15688
    {
15689
        switch (m_type)
15690
        {
15691
            case value_t::number_integer:
15692
            {
15693
                m_value.number_integer = 0;
15694
                break;
15695
            }
15696
15697
            case value_t::number_unsigned:
15698
            {
15699
                m_value.number_unsigned = 0;
15700
                break;
15701
            }
15702
15703
            case value_t::number_float:
15704
            {
15705
                m_value.number_float = 0.0;
15706
                break;
15707
            }
15708
15709
            case value_t::boolean:
15710
            {
15711
                m_value.boolean = false;
15712
                break;
15713
            }
15714
15715
            case value_t::string:
15716
            {
15717
                m_value.string->clear();
15718
                break;
15719
            }
15720
15721
            case value_t::array:
15722
            {
15723
                m_value.array->clear();
15724
                break;
15725
            }
15726
15727
            case value_t::object:
15728
            {
15729
                m_value.object->clear();
15730
                break;
15731
            }
15732
15733
            default:
15734
                break;
15735
        }
15736
    }
15737
15738
    /*!
15739
    @brief add an object to an array
15740
15741
    Appends the given element @a val to the end of the JSON value. If the
15742
    function is called on a JSON null value, an empty array is created before
15743
    appending @a val.
15744
15745
    @param[in] val the value to add to the JSON array
15746
15747
    @throw type_error.308 when called on a type other than JSON array or
15748
    null; example: `"cannot use push_back() with number"`
15749
15750
    @complexity Amortized constant.
15751
15752
    @liveexample{The example shows how `push_back()` and `+=` can be used to
15753
    add elements to a JSON array. Note how the `null` value was silently
15754
    converted to a JSON array.,push_back}
15755
15756
    @since version 1.0.0
15757
    */
15758
    void push_back(basic_json&& val)
15759
    {
15760
        // push_back only works for null objects or arrays
15761
        if (JSON_UNLIKELY(not(is_null() or is_array())))
15762
        {
15763
            JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
15764
        }
15765
15766
        // transform null object into an array
15767
        if (is_null())
15768
        {
15769
            m_type = value_t::array;
15770
            m_value = value_t::array;
15771
            assert_invariant();
15772
        }
15773
15774
        // add element to array (move semantics)
15775
        m_value.array->push_back(std::move(val));
15776
        // invalidate object
15777
        val.m_type = value_t::null;
15778
    }
15779
15780
    /*!
15781
    @brief add an object to an array
15782
    @copydoc push_back(basic_json&&)
15783
    */
15784
    reference operator+=(basic_json&& val)
15785
    {
15786
        push_back(std::move(val));
15787
        return *this;
15788
    }
15789
15790
    /*!
15791
    @brief add an object to an array
15792
    @copydoc push_back(basic_json&&)
15793
    */
15794
    void push_back(const basic_json& val)
15795
    {
15796
        // push_back only works for null objects or arrays
15797
        if (JSON_UNLIKELY(not(is_null() or is_array())))
15798
        {
15799
            JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
15800
        }
15801
15802
        // transform null object into an array
15803
        if (is_null())
15804
        {
15805
            m_type = value_t::array;
15806
            m_value = value_t::array;
15807
            assert_invariant();
15808
        }
15809
15810
        // add element to array
15811
        m_value.array->push_back(val);
15812
    }
15813
15814
    /*!
15815
    @brief add an object to an array
15816
    @copydoc push_back(basic_json&&)
15817
    */
15818
    reference operator+=(const basic_json& val)
15819
    {
15820
        push_back(val);
15821
        return *this;
15822
    }
15823
15824
    /*!
15825
    @brief add an object to an object
15826
15827
    Inserts the given element @a val to the JSON object. If the function is
15828
    called on a JSON null value, an empty object is created before inserting
15829
    @a val.
15830
15831
    @param[in] val the value to add to the JSON object
15832
15833
    @throw type_error.308 when called on a type other than JSON object or
15834
    null; example: `"cannot use push_back() with number"`
15835
15836
    @complexity Logarithmic in the size of the container, O(log(`size()`)).
15837
15838
    @liveexample{The example shows how `push_back()` and `+=` can be used to
15839
    add elements to a JSON object. Note how the `null` value was silently
15840
    converted to a JSON object.,push_back__object_t__value}
15841
15842
    @since version 1.0.0
15843
    */
15844
    void push_back(const typename object_t::value_type& val)
15845
    {
15846
        // push_back only works for null objects or objects
15847
        if (JSON_UNLIKELY(not(is_null() or is_object())))
15848
        {
15849
            JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
15850
        }
15851
15852
        // transform null object into an object
15853
        if (is_null())
15854
        {
15855
            m_type = value_t::object;
15856
            m_value = value_t::object;
15857
            assert_invariant();
15858
        }
15859
15860
        // add element to array
15861
        m_value.object->insert(val);
15862
    }
15863
15864
    /*!
15865
    @brief add an object to an object
15866
    @copydoc push_back(const typename object_t::value_type&)
15867
    */
15868
    reference operator+=(const typename object_t::value_type& val)
15869
    {
15870
        push_back(val);
15871
        return *this;
15872
    }
15873
15874
    /*!
15875
    @brief add an object to an object
15876
15877
    This function allows to use `push_back` with an initializer list. In case
15878
15879
    1. the current value is an object,
15880
    2. the initializer list @a init contains only two elements, and
15881
    3. the first element of @a init is a string,
15882
15883
    @a init is converted into an object element and added using
15884
    @ref push_back(const typename object_t::value_type&). Otherwise, @a init
15885
    is converted to a JSON value and added using @ref push_back(basic_json&&).
15886
15887
    @param[in] init  an initializer list
15888
15889
    @complexity Linear in the size of the initializer list @a init.
15890
15891
    @note This function is required to resolve an ambiguous overload error,
15892
          because pairs like `{"key", "value"}` can be both interpreted as
15893
          `object_t::value_type` or `std::initializer_list<basic_json>`, see
15894
          https://github.com/nlohmann/json/issues/235 for more information.
15895
15896
    @liveexample{The example shows how initializer lists are treated as
15897
    objects when possible.,push_back__initializer_list}
15898
    */
15899
    void push_back(initializer_list_t init)
15900
    {
15901
        if (is_object() and init.size() == 2 and (*init.begin())->is_string())
15902
        {
15903
            basic_json&& key = init.begin()->moved_or_copied();
15904
            push_back(typename object_t::value_type(
15905
                          std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
15906
        }
15907
        else
15908
        {
15909
            push_back(basic_json(init));
15910
        }
15911
    }
15912
15913
    /*!
15914
    @brief add an object to an object
15915
    @copydoc push_back(initializer_list_t)
15916
    */
15917
    reference operator+=(initializer_list_t init)
15918
    {
15919
        push_back(init);
15920
        return *this;
15921
    }
15922
15923
    /*!
15924
    @brief add an object to an array
15925
15926
    Creates a JSON value from the passed parameters @a args to the end of the
15927
    JSON value. If the function is called on a JSON null value, an empty array
15928
    is created before appending the value created from @a args.
15929
15930
    @param[in] args arguments to forward to a constructor of @ref basic_json
15931
    @tparam Args compatible types to create a @ref basic_json object
15932
15933
    @throw type_error.311 when called on a type other than JSON array or
15934
    null; example: `"cannot use emplace_back() with number"`
15935
15936
    @complexity Amortized constant.
15937
15938
    @liveexample{The example shows how `push_back()` can be used to add
15939
    elements to a JSON array. Note how the `null` value was silently converted
15940
    to a JSON array.,emplace_back}
15941
15942
    @since version 2.0.8
15943
    */
15944
    template<class... Args>
15945
    void emplace_back(Args&& ... args)
15946
    {
15947
        // emplace_back only works for null objects or arrays
15948
        if (JSON_UNLIKELY(not(is_null() or is_array())))
15949
        {
15950
            JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name())));
15951
        }
15952
15953
        // transform null object into an array
15954
        if (is_null())
15955
        {
15956
            m_type = value_t::array;
15957
            m_value = value_t::array;
15958
            assert_invariant();
15959
        }
15960
15961
        // add element to array (perfect forwarding)
15962
        m_value.array->emplace_back(std::forward<Args>(args)...);
15963
    }
15964
15965
    /*!
15966
    @brief add an object to an object if key does not exist
15967
15968
    Inserts a new element into a JSON object constructed in-place with the
15969
    given @a args if there is no element with the key in the container. If the
15970
    function is called on a JSON null value, an empty object is created before
15971
    appending the value created from @a args.
15972
15973
    @param[in] args arguments to forward to a constructor of @ref basic_json
15974
    @tparam Args compatible types to create a @ref basic_json object
15975
15976
    @return a pair consisting of an iterator to the inserted element, or the
15977
            already-existing element if no insertion happened, and a bool
15978
            denoting whether the insertion took place.
15979
15980
    @throw type_error.311 when called on a type other than JSON object or
15981
    null; example: `"cannot use emplace() with number"`
15982
15983
    @complexity Logarithmic in the size of the container, O(log(`size()`)).
15984
15985
    @liveexample{The example shows how `emplace()` can be used to add elements
15986
    to a JSON object. Note how the `null` value was silently converted to a
15987
    JSON object. Further note how no value is added if there was already one
15988
    value stored with the same key.,emplace}
15989
15990
    @since version 2.0.8
15991
    */
15992
    template<class... Args>
15993
    std::pair<iterator, bool> emplace(Args&& ... args)
15994
    {
15995
        // emplace only works for null objects or arrays
15996
        if (JSON_UNLIKELY(not(is_null() or is_object())))
15997
        {
15998
            JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name())));
15999
        }
16000
16001
        // transform null object into an object
16002
        if (is_null())
16003
        {
16004
            m_type = value_t::object;
16005
            m_value = value_t::object;
16006
            assert_invariant();
16007
        }
16008
16009
        // add element to array (perfect forwarding)
16010
        auto res = m_value.object->emplace(std::forward<Args>(args)...);
16011
        // create result iterator and set iterator to the result of emplace
16012
        auto it = begin();
16013
        it.m_it.object_iterator = res.first;
16014
16015
        // return pair of iterator and boolean
16016
        return {it, res.second};
16017
    }
16018
16019
    /*!
16020
    @brief inserts element
16021
16022
    Inserts element @a val before iterator @a pos.
16023
16024
    @param[in] pos iterator before which the content will be inserted; may be
16025
    the end() iterator
16026
    @param[in] val element to insert
16027
    @return iterator pointing to the inserted @a val.
16028
16029
    @throw type_error.309 if called on JSON values other than arrays;
16030
    example: `"cannot use insert() with string"`
16031
    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
16032
    example: `"iterator does not fit current value"`
16033
16034
    @complexity Constant plus linear in the distance between @a pos and end of
16035
    the container.
16036
16037
    @liveexample{The example shows how `insert()` is used.,insert}
16038
16039
    @since version 1.0.0
16040
    */
16041
    iterator insert(const_iterator pos, const basic_json& val)
16042
    {
16043
        // insert only works for arrays
16044
        if (JSON_LIKELY(is_array()))
16045
        {
16046
            // check if iterator pos fits to this JSON value
16047
            if (JSON_UNLIKELY(pos.m_object != this))
16048
            {
16049
                JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
16050
            }
16051
16052
            // insert to array and return iterator
16053
            iterator result(this);
16054
            result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
16055
            return result;
16056
        }
16057
16058
        JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
16059
    }
16060
16061
    /*!
16062
    @brief inserts element
16063
    @copydoc insert(const_iterator, const basic_json&)
16064
    */
16065
    iterator insert(const_iterator pos, basic_json&& val)
16066
    {
16067
        return insert(pos, val);
16068
    }
16069
16070
    /*!
16071
    @brief inserts elements
16072
16073
    Inserts @a cnt copies of @a val before iterator @a pos.
16074
16075
    @param[in] pos iterator before which the content will be inserted; may be
16076
    the end() iterator
16077
    @param[in] cnt number of copies of @a val to insert
16078
    @param[in] val element to insert
16079
    @return iterator pointing to the first element inserted, or @a pos if
16080
    `cnt==0`
16081
16082
    @throw type_error.309 if called on JSON values other than arrays; example:
16083
    `"cannot use insert() with string"`
16084
    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
16085
    example: `"iterator does not fit current value"`
16086
16087
    @complexity Linear in @a cnt plus linear in the distance between @a pos
16088
    and end of the container.
16089
16090
    @liveexample{The example shows how `insert()` is used.,insert__count}
16091
16092
    @since version 1.0.0
16093
    */
16094
    iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
16095
    {
16096
        // insert only works for arrays
16097
        if (JSON_LIKELY(is_array()))
16098
        {
16099
            // check if iterator pos fits to this JSON value
16100
            if (JSON_UNLIKELY(pos.m_object != this))
16101
            {
16102
                JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
16103
            }
16104
16105
            // insert to array and return iterator
16106
            iterator result(this);
16107
            result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
16108
            return result;
16109
        }
16110
16111
        JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
16112
    }
16113
16114
    /*!
16115
    @brief inserts elements
16116
16117
    Inserts elements from range `[first, last)` before iterator @a pos.
16118
16119
    @param[in] pos iterator before which the content will be inserted; may be
16120
    the end() iterator
16121
    @param[in] first begin of the range of elements to insert
16122
    @param[in] last end of the range of elements to insert
16123
16124
    @throw type_error.309 if called on JSON values other than arrays; example:
16125
    `"cannot use insert() with string"`
16126
    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
16127
    example: `"iterator does not fit current value"`
16128
    @throw invalid_iterator.210 if @a first and @a last do not belong to the
16129
    same JSON value; example: `"iterators do not fit"`
16130
    @throw invalid_iterator.211 if @a first or @a last are iterators into
16131
    container for which insert is called; example: `"passed iterators may not
16132
    belong to container"`
16133
16134
    @return iterator pointing to the first element inserted, or @a pos if
16135
    `first==last`
16136
16137
    @complexity Linear in `std::distance(first, last)` plus linear in the
16138
    distance between @a pos and end of the container.
16139
16140
    @liveexample{The example shows how `insert()` is used.,insert__range}
16141
16142
    @since version 1.0.0
16143
    */
16144
    iterator insert(const_iterator pos, const_iterator first, const_iterator last)
16145
    {
16146
        // insert only works for arrays
16147
        if (JSON_UNLIKELY(not is_array()))
16148
        {
16149
            JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
16150
        }
16151
16152
        // check if iterator pos fits to this JSON value
16153
        if (JSON_UNLIKELY(pos.m_object != this))
16154
        {
16155
            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
16156
        }
16157
16158
        // check if range iterators belong to the same JSON object
16159
        if (JSON_UNLIKELY(first.m_object != last.m_object))
16160
        {
16161
            JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
16162
        }
16163
16164
        if (JSON_UNLIKELY(first.m_object == this))
16165
        {
16166
            JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container"));
16167
        }
16168
16169
        // insert to array and return iterator
16170
        iterator result(this);
16171
        result.m_it.array_iterator = m_value.array->insert(
16172
                                         pos.m_it.array_iterator,
16173
                                         first.m_it.array_iterator,
16174
                                         last.m_it.array_iterator);
16175
        return result;
16176
    }
16177
16178
    /*!
16179
    @brief inserts elements
16180
16181
    Inserts elements from initializer list @a ilist before iterator @a pos.
16182
16183
    @param[in] pos iterator before which the content will be inserted; may be
16184
    the end() iterator
16185
    @param[in] ilist initializer list to insert the values from
16186
16187
    @throw type_error.309 if called on JSON values other than arrays; example:
16188
    `"cannot use insert() with string"`
16189
    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
16190
    example: `"iterator does not fit current value"`
16191
16192
    @return iterator pointing to the first element inserted, or @a pos if
16193
    `ilist` is empty
16194
16195
    @complexity Linear in `ilist.size()` plus linear in the distance between
16196
    @a pos and end of the container.
16197
16198
    @liveexample{The example shows how `insert()` is used.,insert__ilist}
16199
16200
    @since version 1.0.0
16201
    */
16202
    iterator insert(const_iterator pos, initializer_list_t ilist)
16203
    {
16204
        // insert only works for arrays
16205
        if (JSON_UNLIKELY(not is_array()))
16206
        {
16207
            JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
16208
        }
16209
16210
        // check if iterator pos fits to this JSON value
16211
        if (JSON_UNLIKELY(pos.m_object != this))
16212
        {
16213
            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
16214
        }
16215
16216
        // insert to array and return iterator
16217
        iterator result(this);
16218
        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end());
16219
        return result;
16220
    }
16221
16222
    /*!
16223
    @brief inserts elements
16224
16225
    Inserts elements from range `[first, last)`.
16226
16227
    @param[in] first begin of the range of elements to insert
16228
    @param[in] last end of the range of elements to insert
16229
16230
    @throw type_error.309 if called on JSON values other than objects; example:
16231
    `"cannot use insert() with string"`
16232
    @throw invalid_iterator.202 if iterator @a first or @a last does does not
16233
    point to an object; example: `"iterators first and last must point to
16234
    objects"`
16235
    @throw invalid_iterator.210 if @a first and @a last do not belong to the
16236
    same JSON value; example: `"iterators do not fit"`
16237
16238
    @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number
16239
    of elements to insert.
16240
16241
    @liveexample{The example shows how `insert()` is used.,insert__range_object}
16242
16243
    @since version 3.0.0
16244
    */
16245
    void insert(const_iterator first, const_iterator last)
16246
    {
16247
        // insert only works for objects
16248
        if (JSON_UNLIKELY(not is_object()))
16249
        {
16250
            JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
16251
        }
16252
16253
        // check if range iterators belong to the same JSON object
16254
        if (JSON_UNLIKELY(first.m_object != last.m_object))
16255
        {
16256
            JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
16257
        }
16258
16259
        // passed iterators must belong to objects
16260
        if (JSON_UNLIKELY(not first.m_object->is_object()))
16261
        {
16262
            JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
16263
        }
16264
16265
        m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
16266
    }
16267
16268
    /*!
16269
    @brief updates a JSON object from another object, overwriting existing keys
16270
16271
    Inserts all values from JSON object @a j and overwrites existing keys.
16272
16273
    @param[in] j  JSON object to read values from
16274
16275
    @throw type_error.312 if called on JSON values other than objects; example:
16276
    `"cannot use update() with string"`
16277
16278
    @complexity O(N*log(size() + N)), where N is the number of elements to
16279
                insert.
16280
16281
    @liveexample{The example shows how `update()` is used.,update}
16282
16283
    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
16284
16285
    @since version 3.0.0
16286
    */
16287
    void update(const_reference j)
16288
    {
16289
        // implicitly convert null value to an empty object
16290
        if (is_null())
16291
        {
16292
            m_type = value_t::object;
16293
            m_value.object = create<object_t>();
16294
            assert_invariant();
16295
        }
16296
16297
        if (JSON_UNLIKELY(not is_object()))
16298
        {
16299
            JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
16300
        }
16301
        if (JSON_UNLIKELY(not j.is_object()))
16302
        {
16303
            JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name())));
16304
        }
16305
16306
        for (auto it = j.cbegin(); it != j.cend(); ++it)
16307
        {
16308
            m_value.object->operator[](it.key()) = it.value();
16309
        }
16310
    }
16311
16312
    /*!
16313
    @brief updates a JSON object from another object, overwriting existing keys
16314
16315
    Inserts all values from from range `[first, last)` and overwrites existing
16316
    keys.
16317
16318
    @param[in] first begin of the range of elements to insert
16319
    @param[in] last end of the range of elements to insert
16320
16321
    @throw type_error.312 if called on JSON values other than objects; example:
16322
    `"cannot use update() with string"`
16323
    @throw invalid_iterator.202 if iterator @a first or @a last does does not
16324
    point to an object; example: `"iterators first and last must point to
16325
    objects"`
16326
    @throw invalid_iterator.210 if @a first and @a last do not belong to the
16327
    same JSON value; example: `"iterators do not fit"`
16328
16329
    @complexity O(N*log(size() + N)), where N is the number of elements to
16330
                insert.
16331
16332
    @liveexample{The example shows how `update()` is used__range.,update}
16333
16334
    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
16335
16336
    @since version 3.0.0
16337
    */
16338
    void update(const_iterator first, const_iterator last)
16339
    {
16340
        // implicitly convert null value to an empty object
16341
        if (is_null())
16342
        {
16343
            m_type = value_t::object;
16344
            m_value.object = create<object_t>();
16345
            assert_invariant();
16346
        }
16347
16348
        if (JSON_UNLIKELY(not is_object()))
16349
        {
16350
            JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
16351
        }
16352
16353
        // check if range iterators belong to the same JSON object
16354
        if (JSON_UNLIKELY(first.m_object != last.m_object))
16355
        {
16356
            JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
16357
        }
16358
16359
        // passed iterators must belong to objects
16360
        if (JSON_UNLIKELY(not first.m_object->is_object()
16361
                          or not last.m_object->is_object()))
16362
        {
16363
            JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
16364
        }
16365
16366
        for (auto it = first; it != last; ++it)
16367
        {
16368
            m_value.object->operator[](it.key()) = it.value();
16369
        }
16370
    }
16371
16372
    /*!
16373
    @brief exchanges the values
16374
16375
    Exchanges the contents of the JSON value with those of @a other. Does not
16376
    invoke any move, copy, or swap operations on individual elements. All
16377
    iterators and references remain valid. The past-the-end iterator is
16378
    invalidated.
16379
16380
    @param[in,out] other JSON value to exchange the contents with
16381
16382
    @complexity Constant.
16383
16384
    @liveexample{The example below shows how JSON values can be swapped with
16385
    `swap()`.,swap__reference}
16386
16387
    @since version 1.0.0
16388
    */
16389
    void swap(reference other) noexcept (
16390
        std::is_nothrow_move_constructible<value_t>::value and
16391
        std::is_nothrow_move_assignable<value_t>::value and
16392
        std::is_nothrow_move_constructible<json_value>::value and
16393
        std::is_nothrow_move_assignable<json_value>::value
16394
    )
0
16395
    {
0
16396
        std::swap(m_type, other.m_type);
0
16397
        std::swap(m_value, other.m_value);
0
16398
        assert_invariant();
0
16399
    }
16400
16401
    /*!
16402
    @brief exchanges the values
16403
16404
    Exchanges the contents of a JSON array with those of @a other. Does not
16405
    invoke any move, copy, or swap operations on individual elements. All
16406
    iterators and references remain valid. The past-the-end iterator is
16407
    invalidated.
16408
16409
    @param[in,out] other array to exchange the contents with
16410
16411
    @throw type_error.310 when JSON value is not an array; example: `"cannot
16412
    use swap() with string"`
16413
16414
    @complexity Constant.
16415
16416
    @liveexample{The example below shows how arrays can be swapped with
16417
    `swap()`.,swap__array_t}
16418
16419
    @since version 1.0.0
16420
    */
16421
    void swap(array_t& other)
16422
    {
16423
        // swap only works for arrays
16424
        if (JSON_LIKELY(is_array()))
16425
        {
16426
            std::swap(*(m_value.array), other);
16427
        }
16428
        else
16429
        {
16430
            JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name())));
16431
        }
16432
    }
16433
16434
    /*!
16435
    @brief exchanges the values
16436
16437
    Exchanges the contents of a JSON object with those of @a other. Does not
16438
    invoke any move, copy, or swap operations on individual elements. All
16439
    iterators and references remain valid. The past-the-end iterator is
16440
    invalidated.
16441
16442
    @param[in,out] other object to exchange the contents with
16443
16444
    @throw type_error.310 when JSON value is not an object; example:
16445
    `"cannot use swap() with string"`
16446
16447
    @complexity Constant.
16448
16449
    @liveexample{The example below shows how objects can be swapped with
16450
    `swap()`.,swap__object_t}
16451
16452
    @since version 1.0.0
16453
    */
16454
    void swap(object_t& other)
16455
    {
16456
        // swap only works for objects
16457
        if (JSON_LIKELY(is_object()))
16458
        {
16459
            std::swap(*(m_value.object), other);
16460
        }
16461
        else
16462
        {
16463
            JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name())));
16464
        }
16465
    }
16466
16467
    /*!
16468
    @brief exchanges the values
16469
16470
    Exchanges the contents of a JSON string with those of @a other. Does not
16471
    invoke any move, copy, or swap operations on individual elements. All
16472
    iterators and references remain valid. The past-the-end iterator is
16473
    invalidated.
16474
16475
    @param[in,out] other string to exchange the contents with
16476
16477
    @throw type_error.310 when JSON value is not a string; example: `"cannot
16478
    use swap() with boolean"`
16479
16480
    @complexity Constant.
16481
16482
    @liveexample{The example below shows how strings can be swapped with
16483
    `swap()`.,swap__string_t}
16484
16485
    @since version 1.0.0
16486
    */
16487
    void swap(string_t& other)
16488
    {
16489
        // swap only works for strings
16490
        if (JSON_LIKELY(is_string()))
16491
        {
16492
            std::swap(*(m_value.string), other);
16493
        }
16494
        else
16495
        {
16496
            JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name())));
16497
        }
16498
    }
16499
16500
    /// @}
16501
16502
  public:
16503
    //////////////////////////////////////////
16504
    // lexicographical comparison operators //
16505
    //////////////////////////////////////////
16506
16507
    /// @name lexicographical comparison operators
16508
    /// @{
16509
16510
    /*!
16511
    @brief comparison: equal
16512
16513
    Compares two JSON values for equality according to the following rules:
16514
    - Two JSON values are equal if (1) they are from the same type and (2)
16515
      their stored values are the same according to their respective
16516
      `operator==`.
16517
    - Integer and floating-point numbers are automatically converted before
16518
      comparison. Note than two NaN values are always treated as unequal.
16519
    - Two JSON null values are equal.
16520
16521
    @note Floating-point inside JSON values numbers are compared with
16522
    `json::number_float_t::operator==` which is `double::operator==` by
16523
    default. To compare floating-point while respecting an epsilon, an alternative
16524
    [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39)
16525
    could be used, for instance
16526
    @code {.cpp}
16527
    template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>
16528
    inline bool is_same(T a, T b, T epsilon = std::numeric_limits<T>::epsilon()) noexcept
16529
    {
16530
        return std::abs(a - b) <= epsilon;
16531
    }
16532
    @endcode
16533
16534
    @note NaN values never compare equal to themselves or to other NaN values.
16535
16536
    @param[in] lhs  first JSON value to consider
16537
    @param[in] rhs  second JSON value to consider
16538
    @return whether the values @a lhs and @a rhs are equal
16539
16540
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16541
16542
    @complexity Linear.
16543
16544
    @liveexample{The example demonstrates comparing several JSON
16545
    types.,operator__equal}
16546
16547
    @since version 1.0.0
16548
    */
16549
    friend bool operator==(const_reference lhs, const_reference rhs) noexcept
10
16550
    {
10
16551
        const auto lhs_type = lhs.type();
10
16552
        const auto rhs_type = rhs.type();
10
16553
10
16554
        if (lhs_type == rhs_type)
10
16555
        {
0
16556
            switch (lhs_type)
0
16557
            {
0
16558
                case value_t::array:
0
16559
                    return (*lhs.m_value.array == *rhs.m_value.array);
0
16560
0
16561
                case value_t::object:
0
16562
                    return (*lhs.m_value.object == *rhs.m_value.object);
0
16563
0
16564
                case value_t::null:
0
16565
                    return true;
0
16566
10
16567
                case value_t::string:
10
16568
                    return (*lhs.m_value.string == *rhs.m_value.string);
0
16569
0
16570
                case value_t::boolean:
0
16571
                    return (lhs.m_value.boolean == rhs.m_value.boolean);
0
16572
0
16573
                case value_t::number_integer:
0
16574
                    return (lhs.m_value.number_integer == rhs.m_value.number_integer);
0
16575
0
16576
                case value_t::number_unsigned:
0
16577
                    return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned);
0
16578
0
16579
                case value_t::number_float:
0
16580
                    return (lhs.m_value.number_float == rhs.m_value.number_float);
0
16581
0
16582
                default:
0
16583
                    return false;
0
16584
            }
10
16585
        }
0
16586
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
0
16587
        {
0
16588
            return (static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float);
0
16589
        }
0
16590
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
0
16591
        {
0
16592
            return (lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer));
0
16593
        }
0
16594
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
0
16595
        {
0
16596
            return (static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float);
0
16597
        }
0
16598
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
0
16599
        {
0
16600
            return (lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned));
0
16601
        }
0
16602
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
0
16603
        {
0
16604
            return (static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer);
0
16605
        }
0
16606
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
0
16607
        {
0
16608
            return (lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned));
0
16609
        }
10
16610
0
16611
        return false;
10
16612
    }
16613
16614
    /*!
16615
    @brief comparison: equal
16616
    @copydoc operator==(const_reference, const_reference)
16617
    */
16618
    template<typename ScalarType, typename std::enable_if<
16619
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16620
    friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept
10
16621
    {
10
16622
        return (lhs == basic_json(rhs));
10
16623
    }
16624
16625
    /*!
16626
    @brief comparison: equal
16627
    @copydoc operator==(const_reference, const_reference)
16628
    */
16629
    template<typename ScalarType, typename std::enable_if<
16630
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16631
    friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept
16632
    {
16633
        return (basic_json(lhs) == rhs);
16634
    }
16635
16636
    /*!
16637
    @brief comparison: not equal
16638
16639
    Compares two JSON values for inequality by calculating `not (lhs == rhs)`.
16640
16641
    @param[in] lhs  first JSON value to consider
16642
    @param[in] rhs  second JSON value to consider
16643
    @return whether the values @a lhs and @a rhs are not equal
16644
16645
    @complexity Linear.
16646
16647
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16648
16649
    @liveexample{The example demonstrates comparing several JSON
16650
    types.,operator__notequal}
16651
16652
    @since version 1.0.0
16653
    */
16654
    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
16655
    {
16656
        return not (lhs == rhs);
16657
    }
16658
16659
    /*!
16660
    @brief comparison: not equal
16661
    @copydoc operator!=(const_reference, const_reference)
16662
    */
16663
    template<typename ScalarType, typename std::enable_if<
16664
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16665
    friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept
16666
    {
16667
        return (lhs != basic_json(rhs));
16668
    }
16669
16670
    /*!
16671
    @brief comparison: not equal
16672
    @copydoc operator!=(const_reference, const_reference)
16673
    */
16674
    template<typename ScalarType, typename std::enable_if<
16675
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16676
    friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept
16677
    {
16678
        return (basic_json(lhs) != rhs);
16679
    }
16680
16681
    /*!
16682
    @brief comparison: less than
16683
16684
    Compares whether one JSON value @a lhs is less than another JSON value @a
16685
    rhs according to the following rules:
16686
    - If @a lhs and @a rhs have the same type, the values are compared using
16687
      the default `<` operator.
16688
    - Integer and floating-point numbers are automatically converted before
16689
      comparison
16690
    - In case @a lhs and @a rhs have different types, the values are ignored
16691
      and the order of the types is considered, see
16692
      @ref operator<(const value_t, const value_t).
16693
16694
    @param[in] lhs  first JSON value to consider
16695
    @param[in] rhs  second JSON value to consider
16696
    @return whether @a lhs is less than @a rhs
16697
16698
    @complexity Linear.
16699
16700
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16701
16702
    @liveexample{The example demonstrates comparing several JSON
16703
    types.,operator__less}
16704
16705
    @since version 1.0.0
16706
    */
16707
    friend bool operator<(const_reference lhs, const_reference rhs) noexcept
16708
    {
16709
        const auto lhs_type = lhs.type();
16710
        const auto rhs_type = rhs.type();
16711
16712
        if (lhs_type == rhs_type)
16713
        {
16714
            switch (lhs_type)
16715
            {
16716
                case value_t::array:
16717
                    return (*lhs.m_value.array) < (*rhs.m_value.array);
16718
16719
                case value_t::object:
16720
                    return *lhs.m_value.object < *rhs.m_value.object;
16721
16722
                case value_t::null:
16723
                    return false;
16724
16725
                case value_t::string:
16726
                    return *lhs.m_value.string < *rhs.m_value.string;
16727
16728
                case value_t::boolean:
16729
                    return lhs.m_value.boolean < rhs.m_value.boolean;
16730
16731
                case value_t::number_integer:
16732
                    return lhs.m_value.number_integer < rhs.m_value.number_integer;
16733
16734
                case value_t::number_unsigned:
16735
                    return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
16736
16737
                case value_t::number_float:
16738
                    return lhs.m_value.number_float < rhs.m_value.number_float;
16739
16740
                default:
16741
                    return false;
16742
            }
16743
        }
16744
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
16745
        {
16746
            return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
16747
        }
16748
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
16749
        {
16750
            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
16751
        }
16752
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
16753
        {
16754
            return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
16755
        }
16756
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
16757
        {
16758
            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
16759
        }
16760
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
16761
        {
16762
            return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
16763
        }
16764
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
16765
        {
16766
            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
16767
        }
16768
16769
        // We only reach this line if we cannot compare values. In that case,
16770
        // we compare types. Note we have to call the operator explicitly,
16771
        // because MSVC has problems otherwise.
16772
        return operator<(lhs_type, rhs_type);
16773
    }
16774
16775
    /*!
16776
    @brief comparison: less than
16777
    @copydoc operator<(const_reference, const_reference)
16778
    */
16779
    template<typename ScalarType, typename std::enable_if<
16780
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16781
    friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept
16782
    {
16783
        return (lhs < basic_json(rhs));
16784
    }
16785
16786
    /*!
16787
    @brief comparison: less than
16788
    @copydoc operator<(const_reference, const_reference)
16789
    */
16790
    template<typename ScalarType, typename std::enable_if<
16791
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16792
    friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept
16793
    {
16794
        return (basic_json(lhs) < rhs);
16795
    }
16796
16797
    /*!
16798
    @brief comparison: less than or equal
16799
16800
    Compares whether one JSON value @a lhs is less than or equal to another
16801
    JSON value by calculating `not (rhs < lhs)`.
16802
16803
    @param[in] lhs  first JSON value to consider
16804
    @param[in] rhs  second JSON value to consider
16805
    @return whether @a lhs is less than or equal to @a rhs
16806
16807
    @complexity Linear.
16808
16809
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16810
16811
    @liveexample{The example demonstrates comparing several JSON
16812
    types.,operator__greater}
16813
16814
    @since version 1.0.0
16815
    */
16816
    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
16817
    {
16818
        return not (rhs < lhs);
16819
    }
16820
16821
    /*!
16822
    @brief comparison: less than or equal
16823
    @copydoc operator<=(const_reference, const_reference)
16824
    */
16825
    template<typename ScalarType, typename std::enable_if<
16826
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16827
    friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept
16828
    {
16829
        return (lhs <= basic_json(rhs));
16830
    }
16831
16832
    /*!
16833
    @brief comparison: less than or equal
16834
    @copydoc operator<=(const_reference, const_reference)
16835
    */
16836
    template<typename ScalarType, typename std::enable_if<
16837
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16838
    friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept
16839
    {
16840
        return (basic_json(lhs) <= rhs);
16841
    }
16842
16843
    /*!
16844
    @brief comparison: greater than
16845
16846
    Compares whether one JSON value @a lhs is greater than another
16847
    JSON value by calculating `not (lhs <= rhs)`.
16848
16849
    @param[in] lhs  first JSON value to consider
16850
    @param[in] rhs  second JSON value to consider
16851
    @return whether @a lhs is greater than to @a rhs
16852
16853
    @complexity Linear.
16854
16855
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16856
16857
    @liveexample{The example demonstrates comparing several JSON
16858
    types.,operator__lessequal}
16859
16860
    @since version 1.0.0
16861
    */
16862
    friend bool operator>(const_reference lhs, const_reference rhs) noexcept
16863
    {
16864
        return not (lhs <= rhs);
16865
    }
16866
16867
    /*!
16868
    @brief comparison: greater than
16869
    @copydoc operator>(const_reference, const_reference)
16870
    */
16871
    template<typename ScalarType, typename std::enable_if<
16872
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16873
    friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept
16874
    {
16875
        return (lhs > basic_json(rhs));
16876
    }
16877
16878
    /*!
16879
    @brief comparison: greater than
16880
    @copydoc operator>(const_reference, const_reference)
16881
    */
16882
    template<typename ScalarType, typename std::enable_if<
16883
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16884
    friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept
16885
    {
16886
        return (basic_json(lhs) > rhs);
16887
    }
16888
16889
    /*!
16890
    @brief comparison: greater than or equal
16891
16892
    Compares whether one JSON value @a lhs is greater than or equal to another
16893
    JSON value by calculating `not (lhs < rhs)`.
16894
16895
    @param[in] lhs  first JSON value to consider
16896
    @param[in] rhs  second JSON value to consider
16897
    @return whether @a lhs is greater than or equal to @a rhs
16898
16899
    @complexity Linear.
16900
16901
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16902
16903
    @liveexample{The example demonstrates comparing several JSON
16904
    types.,operator__greaterequal}
16905
16906
    @since version 1.0.0
16907
    */
16908
    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
16909
    {
16910
        return not (lhs < rhs);
16911
    }
16912
16913
    /*!
16914
    @brief comparison: greater than or equal
16915
    @copydoc operator>=(const_reference, const_reference)
16916
    */
16917
    template<typename ScalarType, typename std::enable_if<
16918
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16919
    friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept
16920
    {
16921
        return (lhs >= basic_json(rhs));
16922
    }
16923
16924
    /*!
16925
    @brief comparison: greater than or equal
16926
    @copydoc operator>=(const_reference, const_reference)
16927
    */
16928
    template<typename ScalarType, typename std::enable_if<
16929
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16930
    friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept
16931
    {
16932
        return (basic_json(lhs) >= rhs);
16933
    }
16934
16935
    /// @}
16936
16937
    ///////////////////
16938
    // serialization //
16939
    ///////////////////
16940
16941
    /// @name serialization
16942
    /// @{
16943
16944
    /*!
16945
    @brief serialize to stream
16946
16947
    Serialize the given JSON value @a j to the output stream @a o. The JSON
16948
    value will be serialized using the @ref dump member function.
16949
16950
    - The indentation of the output can be controlled with the member variable
16951
      `width` of the output stream @a o. For instance, using the manipulator
16952
      `std::setw(4)` on @a o sets the indentation level to `4` and the
16953
      serialization result is the same as calling `dump(4)`.
16954
16955
    - The indentation character can be controlled with the member variable
16956
      `fill` of the output stream @a o. For instance, the manipulator
16957
      `std::setfill('\\t')` sets indentation to use a tab character rather than
16958
      the default space character.
16959
16960
    @param[in,out] o  stream to serialize to
16961
    @param[in] j  JSON value to serialize
16962
16963
    @return the stream @a o
16964
16965
    @throw type_error.316 if a string stored inside the JSON value is not
16966
                          UTF-8 encoded
16967
16968
    @complexity Linear.
16969
16970
    @liveexample{The example below shows the serialization with different
16971
    parameters to `width` to adjust the indentation level.,operator_serialize}
16972
16973
    @since version 1.0.0; indentation character added in version 3.0.0
16974
    */
16975
    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
39
16976
    {
39
16977
        // read width member and use it as indentation parameter if nonzero
39
16978
        const bool pretty_print = (o.width() > 0);
23
16979
        const auto indentation = (pretty_print ? o.width() : 0);
39
16980
39
16981
        // reset width to 0 for subsequent calls to this stream
39
16982
        o.width(0);
39
16983
39
16984
        // do the actual serialization
39
16985
        serializer s(detail::output_adapter<char>(o), o.fill());
39
16986
        s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
39
16987
        return o;
39
16988
    }
16989
16990
    /*!
16991
    @brief serialize to stream
16992
    @deprecated This stream operator is deprecated and will be removed in
16993
                future 4.0.0 of the library. Please use
16994
                @ref operator<<(std::ostream&, const basic_json&)
16995
                instead; that is, replace calls like `j >> o;` with `o << j;`.
16996
    @since version 1.0.0; deprecated since version 3.0.0
16997
    */
16998
    JSON_DEPRECATED
16999
    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
17000
    {
17001
        return o << j;
17002
    }
17003
17004
    /// @}
17005
17006
17007
    /////////////////////
17008
    // deserialization //
17009
    /////////////////////
17010
17011
    /// @name deserialization
17012
    /// @{
17013
17014
    /*!
17015
    @brief deserialize from a compatible input
17016
17017
    This function reads from a compatible input. Examples are:
17018
    - an array of 1-byte values
17019
    - strings with character/literal type with size of 1 byte
17020
    - input streams
17021
    - container with contiguous storage of 1-byte values. Compatible container
17022
      types include `std::vector`, `std::string`, `std::array`,
17023
      `std::valarray`, and `std::initializer_list`. Furthermore, C-style
17024
      arrays can be used with `std::begin()`/`std::end()`. User-defined
17025
      containers can be used as long as they implement random-access iterators
17026
      and a contiguous storage.
17027
17028
    @pre Each element of the container has a size of 1 byte. Violating this
17029
    precondition yields undefined behavior. **This precondition is enforced
17030
    with a static assertion.**
17031
17032
    @pre The container storage is contiguous. Violating this precondition
17033
    yields undefined behavior. **This precondition is enforced with an
17034
    assertion.**
17035
    @pre Each element of the container has a size of 1 byte. Violating this
17036
    precondition yields undefined behavior. **This precondition is enforced
17037
    with a static assertion.**
17038
17039
    @warning There is no way to enforce all preconditions at compile-time. If
17040
             the function is called with a noncompliant container and with
17041
             assertions switched off, the behavior is undefined and will most
17042
             likely yield segmentation violation.
17043
17044
    @param[in] i  input to read from
17045
    @param[in] cb  a parser callback function of type @ref parser_callback_t
17046
    which is used to control the deserialization by filtering unwanted values
17047
    (optional)
17048
17049
    @return result of the deserialization
17050
17051
    @throw parse_error.101 if a parse error occurs; example: `""unexpected end
17052
    of input; expected string literal""`
17053
    @throw parse_error.102 if to_unicode fails or surrogate error
17054
    @throw parse_error.103 if to_unicode fails
17055
17056
    @complexity Linear in the length of the input. The parser is a predictive
17057
    LL(1) parser. The complexity can be higher if the parser callback function
17058
    @a cb has a super-linear complexity.
17059
17060
    @note A UTF-8 byte order mark is silently ignored.
17061
17062
    @liveexample{The example below demonstrates the `parse()` function reading
17063
    from an array.,parse__array__parser_callback_t}
17064
17065
    @liveexample{The example below demonstrates the `parse()` function with
17066
    and without callback function.,parse__string__parser_callback_t}
17067
17068
    @liveexample{The example below demonstrates the `parse()` function with
17069
    and without callback function.,parse__istream__parser_callback_t}
17070
17071
    @liveexample{The example below demonstrates the `parse()` function reading
17072
    from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
17073
17074
    @since version 2.0.3 (contiguous containers)
17075
    */
17076
    static basic_json parse(detail::input_adapter&& i,
17077
                            const parser_callback_t cb = nullptr,
17078
                            const bool allow_exceptions = true)
201
17079
    {
201
17080
        basic_json result;
201
17081
        parser(i, cb, allow_exceptions).parse(true, result);
201
17082
        return result;
201
17083
    }
17084
17085
    static bool accept(detail::input_adapter&& i)
17086
    {
17087
        return parser(i).accept(true);
17088
    }
17089
17090
    /*!
17091
    @brief generate SAX events
17092
17093
    The SAX event lister must follow the interface of @ref json_sax.
17094
17095
    This function reads from a compatible input. Examples are:
17096
    - an array of 1-byte values
17097
    - strings with character/literal type with size of 1 byte
17098
    - input streams
17099
    - container with contiguous storage of 1-byte values. Compatible container
17100
      types include `std::vector`, `std::string`, `std::array`,
17101
      `std::valarray`, and `std::initializer_list`. Furthermore, C-style
17102
      arrays can be used with `std::begin()`/`std::end()`. User-defined
17103
      containers can be used as long as they implement random-access iterators
17104
      and a contiguous storage.
17105
17106
    @pre Each element of the container has a size of 1 byte. Violating this
17107
    precondition yields undefined behavior. **This precondition is enforced
17108
    with a static assertion.**
17109
17110
    @pre The container storage is contiguous. Violating this precondition
17111
    yields undefined behavior. **This precondition is enforced with an
17112
    assertion.**
17113
    @pre Each element of the container has a size of 1 byte. Violating this
17114
    precondition yields undefined behavior. **This precondition is enforced
17115
    with a static assertion.**
17116
17117
    @warning There is no way to enforce all preconditions at compile-time. If
17118
             the function is called with a noncompliant container and with
17119
             assertions switched off, the behavior is undefined and will most
17120
             likely yield segmentation violation.
17121
17122
    @param[in] i  input to read from
17123
    @param[in,out] sax  SAX event listener
17124
    @param[in] format  the format to parse (JSON, CBOR, MessagePack, or UBJSON)
17125
    @param[in] strict  whether the input has to be consumed completely
17126
17127
    @return return value of the last processed SAX event
17128
17129
    @throw parse_error.101 if a parse error occurs; example: `""unexpected end
17130
    of input; expected string literal""`
17131
    @throw parse_error.102 if to_unicode fails or surrogate error
17132
    @throw parse_error.103 if to_unicode fails
17133
17134
    @complexity Linear in the length of the input. The parser is a predictive
17135
    LL(1) parser. The complexity can be higher if the SAX consumer @a sax has
17136
    a super-linear complexity.
17137
17138
    @note A UTF-8 byte order mark is silently ignored.
17139
17140
    @liveexample{The example below demonstrates the `sax_parse()` function
17141
    reading from string and processing the events with a user-defined SAX
17142
    event consumer.,sax_parse}
17143
17144
    @since version 3.2.0
17145
    */
17146
    template <typename SAX>
17147
    static bool sax_parse(detail::input_adapter&& i, SAX* sax,
17148
                          input_format_t format = input_format_t::json,
17149
                          const bool strict = true)
17150
    {
17151
        assert(sax);
17152
        switch (format)
17153
        {
17154
            case input_format_t::json:
17155
                return parser(std::move(i)).sax_parse(sax, strict);
17156
            default:
17157
                return detail::binary_reader<basic_json, SAX>(std::move(i)).sax_parse(format, sax, strict);
17158
        }
17159
    }
17160
17161
    /*!
17162
    @brief deserialize from an iterator range with contiguous storage
17163
17164
    This function reads from an iterator range of a container with contiguous
17165
    storage of 1-byte values. Compatible container types include
17166
    `std::vector`, `std::string`, `std::array`, `std::valarray`, and
17167
    `std::initializer_list`. Furthermore, C-style arrays can be used with
17168
    `std::begin()`/`std::end()`. User-defined containers can be used as long
17169
    as they implement random-access iterators and a contiguous storage.
17170
17171
    @pre The iterator range is contiguous. Violating this precondition yields
17172
    undefined behavior. **This precondition is enforced with an assertion.**
17173
    @pre Each element in the range has a size of 1 byte. Violating this
17174
    precondition yields undefined behavior. **This precondition is enforced
17175
    with a static assertion.**
17176
17177
    @warning There is no way to enforce all preconditions at compile-time. If
17178
             the function is called with noncompliant iterators and with
17179
             assertions switched off, the behavior is undefined and will most
17180
             likely yield segmentation violation.
17181
17182
    @tparam IteratorType iterator of container with contiguous storage
17183
    @param[in] first  begin of the range to parse (included)
17184
    @param[in] last  end of the range to parse (excluded)
17185
    @param[in] cb  a parser callback function of type @ref parser_callback_t
17186
    which is used to control the deserialization by filtering unwanted values
17187
    (optional)
17188
    @param[in] allow_exceptions  whether to throw exceptions in case of a
17189
    parse error (optional, true by default)
17190
17191
    @return result of the deserialization
17192
17193
    @throw parse_error.101 in case of an unexpected token
17194
    @throw parse_error.102 if to_unicode fails or surrogate error
17195
    @throw parse_error.103 if to_unicode fails
17196
17197
    @complexity Linear in the length of the input. The parser is a predictive
17198
    LL(1) parser. The complexity can be higher if the parser callback function
17199
    @a cb has a super-linear complexity.
17200
17201
    @note A UTF-8 byte order mark is silently ignored.
17202
17203
    @liveexample{The example below demonstrates the `parse()` function reading
17204
    from an iterator range.,parse__iteratortype__parser_callback_t}
17205
17206
    @since version 2.0.3
17207
    */
17208
    template<class IteratorType, typename std::enable_if<
17209
                 std::is_base_of<
17210
                     std::random_access_iterator_tag,
17211
                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
17212
    static basic_json parse(IteratorType first, IteratorType last,
17213
                            const parser_callback_t cb = nullptr,
17214
                            const bool allow_exceptions = true)
0
17215
    {
0
17216
        basic_json result;
0
17217
        parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result);
0
17218
        return result;
0
17219
    }
17220
17221
    template<class IteratorType, typename std::enable_if<
17222
                 std::is_base_of<
17223
                     std::random_access_iterator_tag,
17224
                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
17225
    static bool accept(IteratorType first, IteratorType last)
17226
    {
17227
        return parser(detail::input_adapter(first, last)).accept(true);
17228
    }
17229
17230
    template<class IteratorType, class SAX, typename std::enable_if<
17231
                 std::is_base_of<
17232
                     std::random_access_iterator_tag,
17233
                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
17234
    static bool sax_parse(IteratorType first, IteratorType last, SAX* sax)
17235
    {
17236
        return parser(detail::input_adapter(first, last)).sax_parse(sax);
17237
    }
17238
17239
    /*!
17240
    @brief deserialize from stream
17241
    @deprecated This stream operator is deprecated and will be removed in
17242
                version 4.0.0 of the library. Please use
17243
                @ref operator>>(std::istream&, basic_json&)
17244
                instead; that is, replace calls like `j << i;` with `i >> j;`.
17245
    @since version 1.0.0; deprecated since version 3.0.0
17246
    */
17247
    JSON_DEPRECATED
17248
    friend std::istream& operator<<(basic_json& j, std::istream& i)
17249
    {
17250
        return operator>>(i, j);
17251
    }
17252
17253
    /*!
17254
    @brief deserialize from stream
17255
17256
    Deserializes an input stream to a JSON value.
17257
17258
    @param[in,out] i  input stream to read a serialized JSON value from
17259
    @param[in,out] j  JSON value to write the deserialized input to
17260
17261
    @throw parse_error.101 in case of an unexpected token
17262
    @throw parse_error.102 if to_unicode fails or surrogate error
17263
    @throw parse_error.103 if to_unicode fails
17264
17265
    @complexity Linear in the length of the input. The parser is a predictive
17266
    LL(1) parser.
17267
17268
    @note A UTF-8 byte order mark is silently ignored.
17269
17270
    @liveexample{The example below shows how a JSON value is constructed by
17271
    reading a serialization from a stream.,operator_deserialize}
17272
17273
    @sa parse(std::istream&, const parser_callback_t) for a variant with a
17274
    parser callback function to filter values while parsing
17275
17276
    @since version 1.0.0
17277
    */
17278
    friend std::istream& operator>>(std::istream& i, basic_json& j)
57
17279
    {
57
17280
        parser(detail::input_adapter(i)).parse(false, j);
57
17281
        return i;
57
17282
    }
17283
17284
    /// @}
17285
17286
    ///////////////////////////
17287
    // convenience functions //
17288
    ///////////////////////////
17289
17290
    /*!
17291
    @brief return the type as string
17292
17293
    Returns the type name as string to be used in error messages - usually to
17294
    indicate that a function was called on a wrong JSON type.
17295
17296
    @return a string representation of a the @a m_type member:
17297
            Value type  | return value
17298
            ----------- | -------------
17299
            null        | `"null"`
17300
            boolean     | `"boolean"`
17301
            string      | `"string"`
17302
            number      | `"number"` (for all number types)
17303
            object      | `"object"`
17304
            array       | `"array"`
17305
            discarded   | `"discarded"`
17306
17307
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
17308
17309
    @complexity Constant.
17310
17311
    @liveexample{The following code exemplifies `type_name()` for all JSON
17312
    types.,type_name}
17313
17314
    @sa @ref type() -- return the type of the JSON value
17315
    @sa @ref operator value_t() -- return the type of the JSON value (implicit)
17316
17317
    @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept`
17318
    since 3.0.0
17319
    */
17320
    const char* type_name() const noexcept
0
17321
    {
0
17322
        {
0
17323
            switch (m_type)
0
17324
            {
0
17325
                case value_t::null:
0
17326
                    return "null";
0
17327
                case value_t::object:
0
17328
                    return "object";
0
17329
                case value_t::array:
0
17330
                    return "array";
0
17331
                case value_t::string:
0
17332
                    return "string";
0
17333
                case value_t::boolean:
0
17334
                    return "boolean";
0
17335
                case value_t::discarded:
0
17336
                    return "discarded";
0
17337
                default:
0
17338
                    return "number";
0
17339
            }
0
17340
        }
0
17341
    }
17342
17343
17344
  private:
17345
    //////////////////////
17346
    // member variables //
17347
    //////////////////////
17348
17349
    /// the type of the current element
17350
    value_t m_type = value_t::null;
17351
17352
    /// the value of the current element
17353
    json_value m_value = {};
17354
17355
    //////////////////////////////////////////
17356
    // binary serialization/deserialization //
17357
    //////////////////////////////////////////
17358
17359
    /// @name binary serialization/deserialization support
17360
    /// @{
17361
17362
  public:
17363
    /*!
17364
    @brief create a CBOR serialization of a given JSON value
17365
17366
    Serializes a given JSON value @a j to a byte vector using the CBOR (Concise
17367
    Binary Object Representation) serialization format. CBOR is a binary
17368
    serialization format which aims to be more compact than JSON itself, yet
17369
    more efficient to parse.
17370
17371
    The library uses the following mapping from JSON values types to
17372
    CBOR types according to the CBOR specification (RFC 7049):
17373
17374
    JSON value type | value/range                                | CBOR type                          | first byte
17375
    --------------- | ------------------------------------------ | ---------------------------------- | ---------------
17376
    null            | `null`                                     | Null                               | 0xF6
17377
    boolean         | `true`                                     | True                               | 0xF5
17378
    boolean         | `false`                                    | False                              | 0xF4
17379
    number_integer  | -9223372036854775808..-2147483649          | Negative integer (8 bytes follow)  | 0x3B
17380
    number_integer  | -2147483648..-32769                        | Negative integer (4 bytes follow)  | 0x3A
17381
    number_integer  | -32768..-129                               | Negative integer (2 bytes follow)  | 0x39
17382
    number_integer  | -128..-25                                  | Negative integer (1 byte follow)   | 0x38
17383
    number_integer  | -24..-1                                    | Negative integer                   | 0x20..0x37
17384
    number_integer  | 0..23                                      | Integer                            | 0x00..0x17
17385
    number_integer  | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18
17386
    number_integer  | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19
17387
    number_integer  | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A
17388
    number_integer  | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B
17389
    number_unsigned | 0..23                                      | Integer                            | 0x00..0x17
17390
    number_unsigned | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18
17391
    number_unsigned | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19
17392
    number_unsigned | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A
17393
    number_unsigned | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B
17394
    number_float    | *any value*                                | Double-Precision Float             | 0xFB
17395
    string          | *length*: 0..23                            | UTF-8 string                       | 0x60..0x77
17396
    string          | *length*: 23..255                          | UTF-8 string (1 byte follow)       | 0x78
17397
    string          | *length*: 256..65535                       | UTF-8 string (2 bytes follow)      | 0x79
17398
    string          | *length*: 65536..4294967295                | UTF-8 string (4 bytes follow)      | 0x7A
17399
    string          | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow)      | 0x7B
17400
    array           | *size*: 0..23                              | array                              | 0x80..0x97
17401
    array           | *size*: 23..255                            | array (1 byte follow)              | 0x98
17402
    array           | *size*: 256..65535                         | array (2 bytes follow)             | 0x99
17403
    array           | *size*: 65536..4294967295                  | array (4 bytes follow)             | 0x9A
17404
    array           | *size*: 4294967296..18446744073709551615   | array (8 bytes follow)             | 0x9B
17405
    object          | *size*: 0..23                              | map                                | 0xA0..0xB7
17406
    object          | *size*: 23..255                            | map (1 byte follow)                | 0xB8
17407
    object          | *size*: 256..65535                         | map (2 bytes follow)               | 0xB9
17408
    object          | *size*: 65536..4294967295                  | map (4 bytes follow)               | 0xBA
17409
    object          | *size*: 4294967296..18446744073709551615   | map (8 bytes follow)               | 0xBB
17410
17411
    @note The mapping is **complete** in the sense that any JSON value type
17412
          can be converted to a CBOR value.
17413
17414
    @note If NaN or Infinity are stored inside a JSON number, they are
17415
          serialized properly. This behavior differs from the @ref dump()
17416
          function which serializes NaN or Infinity to `null`.
17417
17418
    @note The following CBOR types are not used in the conversion:
17419
          - byte strings (0x40..0x5F)
17420
          - UTF-8 strings terminated by "break" (0x7F)
17421
          - arrays terminated by "break" (0x9F)
17422
          - maps terminated by "break" (0xBF)
17423
          - date/time (0xC0..0xC1)
17424
          - bignum (0xC2..0xC3)
17425
          - decimal fraction (0xC4)
17426
          - bigfloat (0xC5)
17427
          - tagged items (0xC6..0xD4, 0xD8..0xDB)
17428
          - expected conversions (0xD5..0xD7)
17429
          - simple values (0xE0..0xF3, 0xF8)
17430
          - undefined (0xF7)
17431
          - half and single-precision floats (0xF9-0xFA)
17432
          - break (0xFF)
17433
17434
    @param[in] j  JSON value to serialize
17435
    @return MessagePack serialization as byte vector
17436
17437
    @complexity Linear in the size of the JSON value @a j.
17438
17439
    @liveexample{The example shows the serialization of a JSON value to a byte
17440
    vector in CBOR format.,to_cbor}
17441
17442
    @sa http://cbor.io
17443
    @sa @ref from_cbor(detail::input_adapter, const bool strict) for the
17444
        analogous deserialization
17445
    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format
17446
    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
17447
             related UBJSON format
17448
17449
    @since version 2.0.9
17450
    */
17451
    static std::vector<uint8_t> to_cbor(const basic_json& j)
17452
    {
17453
        std::vector<uint8_t> result;
17454
        to_cbor(j, result);
17455
        return result;
17456
    }
17457
17458
    static void to_cbor(const basic_json& j, detail::output_adapter<uint8_t> o)
17459
    {
17460
        binary_writer<uint8_t>(o).write_cbor(j);
17461
    }
17462
17463
    static void to_cbor(const basic_json& j, detail::output_adapter<char> o)
17464
    {
17465
        binary_writer<char>(o).write_cbor(j);
17466
    }
17467
17468
    /*!
17469
    @brief create a MessagePack serialization of a given JSON value
17470
17471
    Serializes a given JSON value @a j to a byte vector using the MessagePack
17472
    serialization format. MessagePack is a binary serialization format which
17473
    aims to be more compact than JSON itself, yet more efficient to parse.
17474
17475
    The library uses the following mapping from JSON values types to
17476
    MessagePack types according to the MessagePack specification:
17477
17478
    JSON value type | value/range                       | MessagePack type | first byte
17479
    --------------- | --------------------------------- | ---------------- | ----------
17480
    null            | `null`                            | nil              | 0xC0
17481
    boolean         | `true`                            | true             | 0xC3
17482
    boolean         | `false`                           | false            | 0xC2
17483
    number_integer  | -9223372036854775808..-2147483649 | int64            | 0xD3
17484
    number_integer  | -2147483648..-32769               | int32            | 0xD2
17485
    number_integer  | -32768..-129                      | int16            | 0xD1
17486
    number_integer  | -128..-33                         | int8             | 0xD0
17487
    number_integer  | -32..-1                           | negative fixint  | 0xE0..0xFF
17488
    number_integer  | 0..127                            | positive fixint  | 0x00..0x7F
17489
    number_integer  | 128..255                          | uint 8           | 0xCC
17490
    number_integer  | 256..65535                        | uint 16          | 0xCD
17491
    number_integer  | 65536..4294967295                 | uint 32          | 0xCE
17492
    number_integer  | 4294967296..18446744073709551615  | uint 64          | 0xCF
17493
    number_unsigned | 0..127                            | positive fixint  | 0x00..0x7F
17494
    number_unsigned | 128..255                          | uint 8           | 0xCC
17495
    number_unsigned | 256..65535                        | uint 16          | 0xCD
17496
    number_unsigned | 65536..4294967295                 | uint 32          | 0xCE
17497
    number_unsigned | 4294967296..18446744073709551615  | uint 64          | 0xCF
17498
    number_float    | *any value*                       | float 64         | 0xCB
17499
    string          | *length*: 0..31                   | fixstr           | 0xA0..0xBF
17500
    string          | *length*: 32..255                 | str 8            | 0xD9
17501
    string          | *length*: 256..65535              | str 16           | 0xDA
17502
    string          | *length*: 65536..4294967295       | str 32           | 0xDB
17503
    array           | *size*: 0..15                     | fixarray         | 0x90..0x9F
17504
    array           | *size*: 16..65535                 | array 16         | 0xDC
17505
    array           | *size*: 65536..4294967295         | array 32         | 0xDD
17506
    object          | *size*: 0..15                     | fix map          | 0x80..0x8F
17507
    object          | *size*: 16..65535                 | map 16           | 0xDE
17508
    object          | *size*: 65536..4294967295         | map 32           | 0xDF
17509
17510
    @note The mapping is **complete** in the sense that any JSON value type
17511
          can be converted to a MessagePack value.
17512
17513
    @note The following values can **not** be converted to a MessagePack value:
17514
          - strings with more than 4294967295 bytes
17515
          - arrays with more than 4294967295 elements
17516
          - objects with more than 4294967295 elements
17517
17518
    @note The following MessagePack types are not used in the conversion:
17519
          - bin 8 - bin 32 (0xC4..0xC6)
17520
          - ext 8 - ext 32 (0xC7..0xC9)
17521
          - float 32 (0xCA)
17522
          - fixext 1 - fixext 16 (0xD4..0xD8)
17523
17524
    @note Any MessagePack output created @ref to_msgpack can be successfully
17525
          parsed by @ref from_msgpack.
17526
17527
    @note If NaN or Infinity are stored inside a JSON number, they are
17528
          serialized properly. This behavior differs from the @ref dump()
17529
          function which serializes NaN or Infinity to `null`.
17530
17531
    @param[in] j  JSON value to serialize
17532
    @return MessagePack serialization as byte vector
17533
17534
    @complexity Linear in the size of the JSON value @a j.
17535
17536
    @liveexample{The example shows the serialization of a JSON value to a byte
17537
    vector in MessagePack format.,to_msgpack}
17538
17539
    @sa http://msgpack.org
17540
    @sa @ref from_msgpack(const std::vector<uint8_t>&, const size_t) for the
17541
        analogous deserialization
17542
    @sa @ref to_cbor(const basic_json& for the related CBOR format
17543
    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
17544
             related UBJSON format
17545
17546
    @since version 2.0.9
17547
    */
17548
    static std::vector<uint8_t> to_msgpack(const basic_json& j)
17549
    {
17550
        std::vector<uint8_t> result;
17551
        to_msgpack(j, result);
17552
        return result;
17553
    }
17554
17555
    static void to_msgpack(const basic_json& j, detail::output_adapter<uint8_t> o)
17556
    {
17557
        binary_writer<uint8_t>(o).write_msgpack(j);
17558
    }
17559
17560
    static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)
17561
    {
17562
        binary_writer<char>(o).write_msgpack(j);
17563
    }
17564
17565
    /*!
17566
    @brief create a UBJSON serialization of a given JSON value
17567
17568
    Serializes a given JSON value @a j to a byte vector using the UBJSON
17569
    (Universal Binary JSON) serialization format. UBJSON aims to be more compact
17570
    than JSON itself, yet more efficient to parse.
17571
17572
    The library uses the following mapping from JSON values types to
17573
    UBJSON types according to the UBJSON specification:
17574
17575
    JSON value type | value/range                       | UBJSON type | marker
17576
    --------------- | --------------------------------- | ----------- | ------
17577
    null            | `null`                            | null        | `Z`
17578
    boolean         | `true`                            | true        | `T`
17579
    boolean         | `false`                           | false       | `F`
17580
    number_integer  | -9223372036854775808..-2147483649 | int64       | `L`
17581
    number_integer  | -2147483648..-32769               | int32       | `l`
17582
    number_integer  | -32768..-129                      | int16       | `I`
17583
    number_integer  | -128..127                         | int8        | `i`
17584
    number_integer  | 128..255                          | uint8       | `U`
17585
    number_integer  | 256..32767                        | int16       | `I`
17586
    number_integer  | 32768..2147483647                 | int32       | `l`
17587
    number_integer  | 2147483648..9223372036854775807   | int64       | `L`
17588
    number_unsigned | 0..127                            | int8        | `i`
17589
    number_unsigned | 128..255                          | uint8       | `U`
17590
    number_unsigned | 256..32767                        | int16       | `I`
17591
    number_unsigned | 32768..2147483647                 | int32       | `l`
17592
    number_unsigned | 2147483648..9223372036854775807   | int64       | `L`
17593
    number_float    | *any value*                       | float64     | `D`
17594
    string          | *with shortest length indicator*  | string      | `S`
17595
    array           | *see notes on optimized format*   | array       | `[`
17596
    object          | *see notes on optimized format*   | map         | `{`
17597
17598
    @note The mapping is **complete** in the sense that any JSON value type
17599
          can be converted to a UBJSON value.
17600
17601
    @note The following values can **not** be converted to a UBJSON value:
17602
          - strings with more than 9223372036854775807 bytes (theoretical)
17603
          - unsigned integer numbers above 9223372036854775807
17604
17605
    @note The following markers are not used in the conversion:
17606
          - `Z`: no-op values are not created.
17607
          - `C`: single-byte strings are serialized with `S` markers.
17608
17609
    @note Any UBJSON output created @ref to_ubjson can be successfully parsed
17610
          by @ref from_ubjson.
17611
17612
    @note If NaN or Infinity are stored inside a JSON number, they are
17613
          serialized properly. This behavior differs from the @ref dump()
17614
          function which serializes NaN or Infinity to `null`.
17615
17616
    @note The optimized formats for containers are supported: Parameter
17617
          @a use_size adds size information to the beginning of a container and
17618
          removes the closing marker. Parameter @a use_type further checks
17619
          whether all elements of a container have the same type and adds the
17620
          type marker to the beginning of the container. The @a use_type
17621
          parameter must only be used together with @a use_size = true. Note
17622
          that @a use_size = true alone may result in larger representations -
17623
          the benefit of this parameter is that the receiving side is
17624
          immediately informed on the number of elements of the container.
17625
17626
    @param[in] j  JSON value to serialize
17627
    @param[in] use_size  whether to add size annotations to container types
17628
    @param[in] use_type  whether to add type annotations to container types
17629
                         (must be combined with @a use_size = true)
17630
    @return UBJSON serialization as byte vector
17631
17632
    @complexity Linear in the size of the JSON value @a j.
17633
17634
    @liveexample{The example shows the serialization of a JSON value to a byte
17635
    vector in UBJSON format.,to_ubjson}
17636
17637
    @sa http://ubjson.org
17638
    @sa @ref from_ubjson(detail::input_adapter, const bool strict) for the
17639
        analogous deserialization
17640
    @sa @ref to_cbor(const basic_json& for the related CBOR format
17641
    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format
17642
17643
    @since version 3.1.0
17644
    */
17645
    static std::vector<uint8_t> to_ubjson(const basic_json& j,
17646
                                          const bool use_size = false,
17647
                                          const bool use_type = false)
17648
    {
17649
        std::vector<uint8_t> result;
17650
        to_ubjson(j, result, use_size, use_type);
17651
        return result;
17652
    }
17653
17654
    static void to_ubjson(const basic_json& j, detail::output_adapter<uint8_t> o,
17655
                          const bool use_size = false, const bool use_type = false)
17656
    {
17657
        binary_writer<uint8_t>(o).write_ubjson(j, use_size, use_type);
17658
    }
17659
17660
    static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
17661
                          const bool use_size = false, const bool use_type = false)
17662
    {
17663
        binary_writer<char>(o).write_ubjson(j, use_size, use_type);
17664
    }
17665
17666
    /*!
17667
    @brief create a JSON value from an input in CBOR format
17668
17669
    Deserializes a given input @a i to a JSON value using the CBOR (Concise
17670
    Binary Object Representation) serialization format.
17671
17672
    The library maps CBOR types to JSON value types as follows:
17673
17674
    CBOR type              | JSON value type | first byte
17675
    ---------------------- | --------------- | ----------
17676
    Integer                | number_unsigned | 0x00..0x17
17677
    Unsigned integer       | number_unsigned | 0x18
17678
    Unsigned integer       | number_unsigned | 0x19
17679
    Unsigned integer       | number_unsigned | 0x1A
17680
    Unsigned integer       | number_unsigned | 0x1B
17681
    Negative integer       | number_integer  | 0x20..0x37
17682
    Negative integer       | number_integer  | 0x38
17683
    Negative integer       | number_integer  | 0x39
17684
    Negative integer       | number_integer  | 0x3A
17685
    Negative integer       | number_integer  | 0x3B
17686
    Negative integer       | number_integer  | 0x40..0x57
17687
    UTF-8 string           | string          | 0x60..0x77
17688
    UTF-8 string           | string          | 0x78
17689
    UTF-8 string           | string          | 0x79
17690
    UTF-8 string           | string          | 0x7A
17691
    UTF-8 string           | string          | 0x7B
17692
    UTF-8 string           | string          | 0x7F
17693
    array                  | array           | 0x80..0x97
17694
    array                  | array           | 0x98
17695
    array                  | array           | 0x99
17696
    array                  | array           | 0x9A
17697
    array                  | array           | 0x9B
17698
    array                  | array           | 0x9F
17699
    map                    | object          | 0xA0..0xB7
17700
    map                    | object          | 0xB8
17701
    map                    | object          | 0xB9
17702
    map                    | object          | 0xBA
17703
    map                    | object          | 0xBB
17704
    map                    | object          | 0xBF
17705
    False                  | `false`         | 0xF4
17706
    True                   | `true`          | 0xF5
17707
    Nill                   | `null`          | 0xF6
17708
    Half-Precision Float   | number_float    | 0xF9
17709
    Single-Precision Float | number_float    | 0xFA
17710
    Double-Precision Float | number_float    | 0xFB
17711
17712
    @warning The mapping is **incomplete** in the sense that not all CBOR
17713
             types can be converted to a JSON value. The following CBOR types
17714
             are not supported and will yield parse errors (parse_error.112):
17715
             - byte strings (0x40..0x5F)
17716
             - date/time (0xC0..0xC1)
17717
             - bignum (0xC2..0xC3)
17718
             - decimal fraction (0xC4)
17719
             - bigfloat (0xC5)
17720
             - tagged items (0xC6..0xD4, 0xD8..0xDB)
17721
             - expected conversions (0xD5..0xD7)
17722
             - simple values (0xE0..0xF3, 0xF8)
17723
             - undefined (0xF7)
17724
17725
    @warning CBOR allows map keys of any type, whereas JSON only allows
17726
             strings as keys in object values. Therefore, CBOR maps with keys
17727
             other than UTF-8 strings are rejected (parse_error.113).
17728
17729
    @note Any CBOR output created @ref to_cbor can be successfully parsed by
17730
          @ref from_cbor.
17731
17732
    @param[in] i  an input in CBOR format convertible to an input adapter
17733
    @param[in] strict  whether to expect the input to be consumed until EOF
17734
                       (true by default)
17735
    @param[in] allow_exceptions  whether to throw exceptions in case of a
17736
    parse error (optional, true by default)
17737
17738
    @return deserialized JSON value
17739
17740
    @throw parse_error.110 if the given input ends prematurely or the end of
17741
    file was not reached when @a strict was set to true
17742
    @throw parse_error.112 if unsupported features from CBOR were
17743
    used in the given input @a v or if the input is not valid CBOR
17744
    @throw parse_error.113 if a string was expected as map key, but not found
17745
17746
    @complexity Linear in the size of the input @a i.
17747
17748
    @liveexample{The example shows the deserialization of a byte vector in CBOR
17749
    format to a JSON value.,from_cbor}
17750
17751
    @sa http://cbor.io
17752
    @sa @ref to_cbor(const basic_json&) for the analogous serialization
17753
    @sa @ref from_msgpack(detail::input_adapter, const bool, const bool) for the
17754
        related MessagePack format
17755
    @sa @ref from_ubjson(detail::input_adapter, const bool, const bool) for the
17756
        related UBJSON format
17757
17758
    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to
17759
           consume input adapters, removed start_index parameter, and added
17760
           @a strict parameter since 3.0.0; added @allow_exceptions parameter
17761
           since 3.2.0
17762
    */
17763
    static basic_json from_cbor(detail::input_adapter&& i,
17764
                                const bool strict = true,
17765
                                const bool allow_exceptions = true)
17766
    {
17767
        basic_json result;
17768
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17769
        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::cbor, &sdp, strict);
17770
        return res ? result : basic_json(value_t::discarded);
17771
    }
17772
17773
    /*!
17774
    @copydoc from_cbor(detail::input_adapter, const bool, const bool)
17775
    */
17776
    template<typename A1, typename A2,
17777
             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
17778
    static basic_json from_cbor(A1 && a1, A2 && a2,
17779
                                const bool strict = true,
17780
                                const bool allow_exceptions = true)
17781
    {
17782
        basic_json result;
17783
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17784
        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::cbor, &sdp, strict);
17785
        return res ? result : basic_json(value_t::discarded);
17786
    }
17787
17788
    /*!
17789
    @brief create a JSON value from an input in MessagePack format
17790
17791
    Deserializes a given input @a i to a JSON value using the MessagePack
17792
    serialization format.
17793
17794
    The library maps MessagePack types to JSON value types as follows:
17795
17796
    MessagePack type | JSON value type | first byte
17797
    ---------------- | --------------- | ----------
17798
    positive fixint  | number_unsigned | 0x00..0x7F
17799
    fixmap           | object          | 0x80..0x8F
17800
    fixarray         | array           | 0x90..0x9F
17801
    fixstr           | string          | 0xA0..0xBF
17802
    nil              | `null`          | 0xC0
17803
    false            | `false`         | 0xC2
17804
    true             | `true`          | 0xC3
17805
    float 32         | number_float    | 0xCA
17806
    float 64         | number_float    | 0xCB
17807
    uint 8           | number_unsigned | 0xCC
17808
    uint 16          | number_unsigned | 0xCD
17809
    uint 32          | number_unsigned | 0xCE
17810
    uint 64          | number_unsigned | 0xCF
17811
    int 8            | number_integer  | 0xD0
17812
    int 16           | number_integer  | 0xD1
17813
    int 32           | number_integer  | 0xD2
17814
    int 64           | number_integer  | 0xD3
17815
    str 8            | string          | 0xD9
17816
    str 16           | string          | 0xDA
17817
    str 32           | string          | 0xDB
17818
    array 16         | array           | 0xDC
17819
    array 32         | array           | 0xDD
17820
    map 16           | object          | 0xDE
17821
    map 32           | object          | 0xDF
17822
    negative fixint  | number_integer  | 0xE0-0xFF
17823
17824
    @warning The mapping is **incomplete** in the sense that not all
17825
             MessagePack types can be converted to a JSON value. The following
17826
             MessagePack types are not supported and will yield parse errors:
17827
              - bin 8 - bin 32 (0xC4..0xC6)
17828
              - ext 8 - ext 32 (0xC7..0xC9)
17829
              - fixext 1 - fixext 16 (0xD4..0xD8)
17830
17831
    @note Any MessagePack output created @ref to_msgpack can be successfully
17832
          parsed by @ref from_msgpack.
17833
17834
    @param[in] i  an input in MessagePack format convertible to an input
17835
                  adapter
17836
    @param[in] strict  whether to expect the input to be consumed until EOF
17837
                       (true by default)
17838
    @param[in] allow_exceptions  whether to throw exceptions in case of a
17839
    parse error (optional, true by default)
17840
17841
    @return deserialized JSON value
17842
17843
    @throw parse_error.110 if the given input ends prematurely or the end of
17844
    file was not reached when @a strict was set to true
17845
    @throw parse_error.112 if unsupported features from MessagePack were
17846
    used in the given input @a i or if the input is not valid MessagePack
17847
    @throw parse_error.113 if a string was expected as map key, but not found
17848
17849
    @complexity Linear in the size of the input @a i.
17850
17851
    @liveexample{The example shows the deserialization of a byte vector in
17852
    MessagePack format to a JSON value.,from_msgpack}
17853
17854
    @sa http://msgpack.org
17855
    @sa @ref to_msgpack(const basic_json&) for the analogous serialization
17856
    @sa @ref from_cbor(detail::input_adapter, const bool, const bool) for the
17857
        related CBOR format
17858
    @sa @ref from_ubjson(detail::input_adapter, const bool, const bool) for
17859
        the related UBJSON format
17860
17861
    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to
17862
           consume input adapters, removed start_index parameter, and added
17863
           @a strict parameter since 3.0.0; added @allow_exceptions parameter
17864
           since 3.2.0
17865
    */
17866
    static basic_json from_msgpack(detail::input_adapter&& i,
17867
                                   const bool strict = true,
17868
                                   const bool allow_exceptions = true)
17869
    {
17870
        basic_json result;
17871
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17872
        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::msgpack, &sdp, strict);
17873
        return res ? result : basic_json(value_t::discarded);
17874
    }
17875
17876
    /*!
17877
    @copydoc from_msgpack(detail::input_adapter, const bool, const bool)
17878
    */
17879
    template<typename A1, typename A2,
17880
             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
17881
    static basic_json from_msgpack(A1 && a1, A2 && a2,
17882
                                   const bool strict = true,
17883
                                   const bool allow_exceptions = true)
17884
    {
17885
        basic_json result;
17886
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17887
        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::msgpack, &sdp, strict);
17888
        return res ? result : basic_json(value_t::discarded);
17889
    }
17890
17891
    /*!
17892
    @brief create a JSON value from an input in UBJSON format
17893
17894
    Deserializes a given input @a i to a JSON value using the UBJSON (Universal
17895
    Binary JSON) serialization format.
17896
17897
    The library maps UBJSON types to JSON value types as follows:
17898
17899
    UBJSON type | JSON value type                         | marker
17900
    ----------- | --------------------------------------- | ------
17901
    no-op       | *no value, next value is read*          | `N`
17902
    null        | `null`                                  | `Z`
17903
    false       | `false`                                 | `F`
17904
    true        | `true`                                  | `T`
17905
    float32     | number_float                            | `d`
17906
    float64     | number_float                            | `D`
17907
    uint8       | number_unsigned                         | `U`
17908
    int8        | number_integer                          | `i`
17909
    int16       | number_integer                          | `I`
17910
    int32       | number_integer                          | `l`
17911
    int64       | number_integer                          | `L`
17912
    string      | string                                  | `S`
17913
    char        | string                                  | `C`
17914
    array       | array (optimized values are supported)  | `[`
17915
    object      | object (optimized values are supported) | `{`
17916
17917
    @note The mapping is **complete** in the sense that any UBJSON value can
17918
          be converted to a JSON value.
17919
17920
    @param[in] i  an input in UBJSON format convertible to an input adapter
17921
    @param[in] strict  whether to expect the input to be consumed until EOF
17922
                       (true by default)
17923
    @param[in] allow_exceptions  whether to throw exceptions in case of a
17924
    parse error (optional, true by default)
17925
17926
    @return deserialized JSON value
17927
17928
    @throw parse_error.110 if the given input ends prematurely or the end of
17929
    file was not reached when @a strict was set to true
17930
    @throw parse_error.112 if a parse error occurs
17931
    @throw parse_error.113 if a string could not be parsed successfully
17932
17933
    @complexity Linear in the size of the input @a i.
17934
17935
    @liveexample{The example shows the deserialization of a byte vector in
17936
    UBJSON format to a JSON value.,from_ubjson}
17937
17938
    @sa http://ubjson.org
17939
    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
17940
             analogous serialization
17941
    @sa @ref from_cbor(detail::input_adapter, const bool, const bool) for the
17942
        related CBOR format
17943
    @sa @ref from_msgpack(detail::input_adapter, const bool, const bool) for
17944
        the related MessagePack format
17945
17946
    @since version 3.1.0; added @allow_exceptions parameter since 3.2.0
17947
    */
17948
    static basic_json from_ubjson(detail::input_adapter&& i,
17949
                                  const bool strict = true,
17950
                                  const bool allow_exceptions = true)
17951
    {
17952
        basic_json result;
17953
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17954
        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::ubjson, &sdp, strict);
17955
        return res ? result : basic_json(value_t::discarded);
17956
    }
17957
17958
    /*!
17959
    @copydoc from_ubjson(detail::input_adapter, const bool, const bool)
17960
    */
17961
    template<typename A1, typename A2,
17962
             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
17963
    static basic_json from_ubjson(A1 && a1, A2 && a2,
17964
                                  const bool strict = true,
17965
                                  const bool allow_exceptions = true)
17966
    {
17967
        basic_json result;
17968
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17969
        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::ubjson, &sdp, strict);
17970
        return res ? result : basic_json(value_t::discarded);
17971
    }
17972
17973
    /// @}
17974
17975
    //////////////////////////
17976
    // JSON Pointer support //
17977
    //////////////////////////
17978
17979
    /// @name JSON Pointer functions
17980
    /// @{
17981
17982
    /*!
17983
    @brief access specified element via JSON Pointer
17984
17985
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
17986
    No bound checking is performed. Similar to @ref operator[](const typename
17987
    object_t::key_type&), `null` values are created in arrays and objects if
17988
    necessary.
17989
17990
    In particular:
17991
    - If the JSON pointer points to an object key that does not exist, it
17992
      is created an filled with a `null` value before a reference to it
17993
      is returned.
17994
    - If the JSON pointer points to an array index that does not exist, it
17995
      is created an filled with a `null` value before a reference to it
17996
      is returned. All indices between the current maximum and the given
17997
      index are also filled with `null`.
17998
    - The special value `-` is treated as a synonym for the index past the
17999
      end.
18000
18001
    @param[in] ptr  a JSON pointer
18002
18003
    @return reference to the element pointed to by @a ptr
18004
18005
    @complexity Constant.
18006
18007
    @throw parse_error.106   if an array index begins with '0'
18008
    @throw parse_error.109   if an array index was not a number
18009
    @throw out_of_range.404  if the JSON pointer can not be resolved
18010
18011
    @liveexample{The behavior is shown in the example.,operatorjson_pointer}
18012
18013
    @since version 2.0.0
18014
    */
18015
    reference operator[](const json_pointer& ptr)
18016
    {
18017
        return ptr.get_unchecked(this);
18018
    }
18019
18020
    /*!
18021
    @brief access specified element via JSON Pointer
18022
18023
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
18024
    No bound checking is performed. The function does not change the JSON
18025
    value; no `null` values are created. In particular, the the special value
18026
    `-` yields an exception.
18027
18028
    @param[in] ptr  JSON pointer to the desired element
18029
18030
    @return const reference to the element pointed to by @a ptr
18031
18032
    @complexity Constant.
18033
18034
    @throw parse_error.106   if an array index begins with '0'
18035
    @throw parse_error.109   if an array index was not a number
18036
    @throw out_of_range.402  if the array index '-' is used
18037
    @throw out_of_range.404  if the JSON pointer can not be resolved
18038
18039
    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
18040
18041
    @since version 2.0.0
18042
    */
18043
    const_reference operator[](const json_pointer& ptr) const
18044
    {
18045
        return ptr.get_unchecked(this);
18046
    }
18047
18048
    /*!
18049
    @brief access specified element via JSON Pointer
18050
18051
    Returns a reference to the element at with specified JSON pointer @a ptr,
18052
    with bounds checking.
18053
18054
    @param[in] ptr  JSON pointer to the desired element
18055
18056
    @return reference to the element pointed to by @a ptr
18057
18058
    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr
18059
    begins with '0'. See example below.
18060
18061
    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr
18062
    is not a number. See example below.
18063
18064
    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr
18065
    is out of range. See example below.
18066
18067
    @throw out_of_range.402 if the array index '-' is used in the passed JSON
18068
    pointer @a ptr. As `at` provides checked access (and no elements are
18069
    implicitly inserted), the index '-' is always invalid. See example below.
18070
18071
    @throw out_of_range.403 if the JSON pointer describes a key of an object
18072
    which cannot be found. See example below.
18073
18074
    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.
18075
    See example below.
18076
18077
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
18078
    changes in the JSON value.
18079
18080
    @complexity Constant.
18081
18082
    @since version 2.0.0
18083
18084
    @liveexample{The behavior is shown in the example.,at_json_pointer}
18085
    */
18086
    reference at(const json_pointer& ptr)
18087
    {
18088
        return ptr.get_checked(this);
18089
    }
18090
18091
    /*!
18092
    @brief access specified element via JSON Pointer
18093
18094
    Returns a const reference to the element at with specified JSON pointer @a
18095
    ptr, with bounds checking.
18096
18097
    @param[in] ptr  JSON pointer to the desired element
18098
18099
    @return reference to the element pointed to by @a ptr
18100
18101
    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr
18102
    begins with '0'. See example below.
18103
18104
    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr
18105
    is not a number. See example below.
18106
18107
    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr
18108
    is out of range. See example below.
18109
18110
    @throw out_of_range.402 if the array index '-' is used in the passed JSON
18111
    pointer @a ptr. As `at` provides checked access (and no elements are
18112
    implicitly inserted), the index '-' is always invalid. See example below.
18113
18114
    @throw out_of_range.403 if the JSON pointer describes a key of an object
18115
    which cannot be found. See example below.
18116
18117
    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.
18118
    See example below.
18119
18120
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
18121
    changes in the JSON value.
18122
18123
    @complexity Constant.
18124
18125
    @since version 2.0.0
18126
18127
    @liveexample{The behavior is shown in the example.,at_json_pointer_const}
18128
    */
18129
    const_reference at(const json_pointer& ptr) const
18130
    {
18131
        return ptr.get_checked(this);
18132
    }
18133
18134
    /*!
18135
    @brief return flattened JSON value
18136
18137
    The function creates a JSON object whose keys are JSON pointers (see [RFC
18138
    6901](https://tools.ietf.org/html/rfc6901)) and whose values are all
18139
    primitive. The original JSON value can be restored using the @ref
18140
    unflatten() function.
18141
18142
    @return an object that maps JSON pointers to primitive values
18143
18144
    @note Empty objects and arrays are flattened to `null` and will not be
18145
          reconstructed correctly by the @ref unflatten() function.
18146
18147
    @complexity Linear in the size the JSON value.
18148
18149
    @liveexample{The following code shows how a JSON object is flattened to an
18150
    object whose keys consist of JSON pointers.,flatten}
18151
18152
    @sa @ref unflatten() for the reverse function
18153
18154
    @since version 2.0.0
18155
    */
18156
    basic_json flatten() const
18157
    {
18158
        basic_json result(value_t::object);
18159
        json_pointer::flatten("", *this, result);
18160
        return result;
18161
    }
18162
18163
    /*!
18164
    @brief unflatten a previously flattened JSON value
18165
18166
    The function restores the arbitrary nesting of a JSON value that has been
18167
    flattened before using the @ref flatten() function. The JSON value must
18168
    meet certain constraints:
18169
    1. The value must be an object.
18170
    2. The keys must be JSON pointers (see
18171
       [RFC 6901](https://tools.ietf.org/html/rfc6901))
18172
    3. The mapped values must be primitive JSON types.
18173
18174
    @return the original JSON from a flattened version
18175
18176
    @note Empty objects and arrays are flattened by @ref flatten() to `null`
18177
          values and can not unflattened to their original type. Apart from
18178
          this example, for a JSON value `j`, the following is always true:
18179
          `j == j.flatten().unflatten()`.
18180
18181
    @complexity Linear in the size the JSON value.
18182
18183
    @throw type_error.314  if value is not an object
18184
    @throw type_error.315  if object values are not primitive
18185
18186
    @liveexample{The following code shows how a flattened JSON object is
18187
    unflattened into the original nested JSON object.,unflatten}
18188
18189
    @sa @ref flatten() for the reverse function
18190
18191
    @since version 2.0.0
18192
    */
18193
    basic_json unflatten() const
18194
    {
18195
        return json_pointer::unflatten(*this);
18196
    }
18197
18198
    /// @}
18199
18200
    //////////////////////////
18201
    // JSON Patch functions //
18202
    //////////////////////////
18203
18204
    /// @name JSON Patch functions
18205
    /// @{
18206
18207
    /*!
18208
    @brief applies a JSON patch
18209
18210
    [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
18211
    expressing a sequence of operations to apply to a JSON) document. With
18212
    this function, a JSON Patch is applied to the current JSON value by
18213
    executing all operations from the patch.
18214
18215
    @param[in] json_patch  JSON patch document
18216
    @return patched document
18217
18218
    @note The application of a patch is atomic: Either all operations succeed
18219
          and the patched document is returned or an exception is thrown. In
18220
          any case, the original value is not changed: the patch is applied
18221
          to a copy of the value.
18222
18223
    @throw parse_error.104 if the JSON patch does not consist of an array of
18224
    objects
18225
18226
    @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory
18227
    attributes are missing); example: `"operation add must have member path"`
18228
18229
    @throw out_of_range.401 if an array index is out of range.
18230
18231
    @throw out_of_range.403 if a JSON pointer inside the patch could not be
18232
    resolved successfully in the current JSON value; example: `"key baz not
18233
    found"`
18234
18235
    @throw out_of_range.405 if JSON pointer has no parent ("add", "remove",
18236
    "move")
18237
18238
    @throw other_error.501 if "test" operation was unsuccessful
18239
18240
    @complexity Linear in the size of the JSON value and the length of the
18241
    JSON patch. As usually only a fraction of the JSON value is affected by
18242
    the patch, the complexity can usually be neglected.
18243
18244
    @liveexample{The following code shows how a JSON patch is applied to a
18245
    value.,patch}
18246
18247
    @sa @ref diff -- create a JSON patch by comparing two JSON values
18248
18249
    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
18250
    @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
18251
18252
    @since version 2.0.0
18253
    */
18254
    basic_json patch(const basic_json& json_patch) const
18255
    {
18256
        // make a working copy to apply the patch to
18257
        basic_json result = *this;
18258
18259
        // the valid JSON Patch operations
18260
        enum class patch_operations {add, remove, replace, move, copy, test, invalid};
18261
18262
        const auto get_op = [](const std::string & op)
18263
        {
18264
            if (op == "add")
18265
            {
18266
                return patch_operations::add;
18267
            }
18268
            if (op == "remove")
18269
            {
18270
                return patch_operations::remove;
18271
            }
18272
            if (op == "replace")
18273
            {
18274
                return patch_operations::replace;
18275
            }
18276
            if (op == "move")
18277
            {
18278
                return patch_operations::move;
18279
            }
18280
            if (op == "copy")
18281
            {
18282
                return patch_operations::copy;
18283
            }
18284
            if (op == "test")
18285
            {
18286
                return patch_operations::test;
18287
            }
18288
18289
            return patch_operations::invalid;
18290
        };
18291
18292
        // wrapper for "add" operation; add value at ptr
18293
        const auto operation_add = [&result](json_pointer & ptr, basic_json val)
18294
        {
18295
            // adding to the root of the target document means replacing it
18296
            if (ptr.is_root())
18297
            {
18298
                result = val;
18299
            }
18300
            else
18301
            {
18302
                // make sure the top element of the pointer exists
18303
                json_pointer top_pointer = ptr.top();
18304
                if (top_pointer != ptr)
18305
                {
18306
                    result.at(top_pointer);
18307
                }
18308
18309
                // get reference to parent of JSON pointer ptr
18310
                const auto last_path = ptr.pop_back();
18311
                basic_json& parent = result[ptr];
18312
18313
                switch (parent.m_type)
18314
                {
18315
                    case value_t::null:
18316
                    case value_t::object:
18317
                    {
18318
                        // use operator[] to add value
18319
                        parent[last_path] = val;
18320
                        break;
18321
                    }
18322
18323
                    case value_t::array:
18324
                    {
18325
                        if (last_path == "-")
18326
                        {
18327
                            // special case: append to back
18328
                            parent.push_back(val);
18329
                        }
18330
                        else
18331
                        {
18332
                            const auto idx = json_pointer::array_index(last_path);
18333
                            if (JSON_UNLIKELY(static_cast<size_type>(idx) > parent.size()))
18334
                            {
18335
                                // avoid undefined behavior
18336
                                JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
18337
                            }
18338
                            else
18339
                            {
18340
                                // default case: insert add offset
18341
                                parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
18342
                            }
18343
                        }
18344
                        break;
18345
                    }
18346
18347
                    // LCOV_EXCL_START
18348
                    default:
18349
                    {
18350
                        // if there exists a parent it cannot be primitive
18351
                        assert(false);
18352
                    }
18353
                        // LCOV_EXCL_STOP
18354
                }
18355
            }
18356
        };
18357
18358
        // wrapper for "remove" operation; remove value at ptr
18359
        const auto operation_remove = [&result](json_pointer & ptr)
18360
        {
18361
            // get reference to parent of JSON pointer ptr
18362
            const auto last_path = ptr.pop_back();
18363
            basic_json& parent = result.at(ptr);
18364
18365
            // remove child
18366
            if (parent.is_object())
18367
            {
18368
                // perform range check
18369
                auto it = parent.find(last_path);
18370
                if (JSON_LIKELY(it != parent.end()))
18371
                {
18372
                    parent.erase(it);
18373
                }
18374
                else
18375
                {
18376
                    JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found"));
18377
                }
18378
            }
18379
            else if (parent.is_array())
18380
            {
18381
                // note erase performs range check
18382
                parent.erase(static_cast<size_type>(json_pointer::array_index(last_path)));
18383
            }
18384
        };
18385
18386
        // type check: top level value must be an array
18387
        if (JSON_UNLIKELY(not json_patch.is_array()))
18388
        {
18389
            JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
18390
        }
18391
18392
        // iterate and apply the operations
18393
        for (const auto& val : json_patch)
18394
        {
18395
            // wrapper to get a value for an operation
18396
            const auto get_value = [&val](const std::string & op,
18397
                                          const std::string & member,
18398
                                          bool string_type) -> basic_json &
18399
            {
18400
                // find value
18401
                auto it = val.m_value.object->find(member);
18402
18403
                // context-sensitive error message
18404
                const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'";
18405
18406
                // check if desired value is present
18407
                if (JSON_UNLIKELY(it == val.m_value.object->end()))
18408
                {
18409
                    JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'"));
18410
                }
18411
18412
                // check if result is of type string
18413
                if (JSON_UNLIKELY(string_type and not it->second.is_string()))
18414
                {
18415
                    JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'"));
18416
                }
18417
18418
                // no error: return value
18419
                return it->second;
18420
            };
18421
18422
            // type check: every element of the array must be an object
18423
            if (JSON_UNLIKELY(not val.is_object()))
18424
            {
18425
                JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
18426
            }
18427
18428
            // collect mandatory members
18429
            const std::string op = get_value("op", "op", true);
18430
            const std::string path = get_value(op, "path", true);
18431
            json_pointer ptr(path);
18432
18433
            switch (get_op(op))
18434
            {
18435
                case patch_operations::add:
18436
                {
18437
                    operation_add(ptr, get_value("add", "value", false));
18438
                    break;
18439
                }
18440
18441
                case patch_operations::remove:
18442
                {
18443
                    operation_remove(ptr);
18444
                    break;
18445
                }
18446
18447
                case patch_operations::replace:
18448
                {
18449
                    // the "path" location must exist - use at()
18450
                    result.at(ptr) = get_value("replace", "value", false);
18451
                    break;
18452
                }
18453
18454
                case patch_operations::move:
18455
                {
18456
                    const std::string from_path = get_value("move", "from", true);
18457
                    json_pointer from_ptr(from_path);
18458
18459
                    // the "from" location must exist - use at()
18460
                    basic_json v = result.at(from_ptr);
18461
18462
                    // The move operation is functionally identical to a
18463
                    // "remove" operation on the "from" location, followed
18464
                    // immediately by an "add" operation at the target
18465
                    // location with the value that was just removed.
18466
                    operation_remove(from_ptr);
18467
                    operation_add(ptr, v);
18468
                    break;
18469
                }
18470
18471
                case patch_operations::copy:
18472
                {
18473
                    const std::string from_path = get_value("copy", "from", true);
18474
                    const json_pointer from_ptr(from_path);
18475
18476
                    // the "from" location must exist - use at()
18477
                    basic_json v = result.at(from_ptr);
18478
18479
                    // The copy is functionally identical to an "add"
18480
                    // operation at the target location using the value
18481
                    // specified in the "from" member.
18482
                    operation_add(ptr, v);
18483
                    break;
18484
                }
18485
18486
                case patch_operations::test:
18487
                {
18488
                    bool success = false;
18489
                    JSON_TRY
18490
                    {
18491
                        // check if "value" matches the one at "path"
18492
                        // the "path" location must exist - use at()
18493
                        success = (result.at(ptr) == get_value("test", "value", false));
18494
                    }
18495
                    JSON_INTERNAL_CATCH (out_of_range&)
18496
                    {
18497
                        // ignore out of range errors: success remains false
18498
                    }
18499
18500
                    // throw an exception if test fails
18501
                    if (JSON_UNLIKELY(not success))
18502
                    {
18503
                        JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump()));
18504
                    }
18505
18506
                    break;
18507
                }
18508
18509
                case patch_operations::invalid:
18510
                {
18511
                    // op must be "add", "remove", "replace", "move", "copy", or
18512
                    // "test"
18513
                    JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid"));
18514
                }
18515
            }
18516
        }
18517
18518
        return result;
18519
    }
18520
18521
    /*!
18522
    @brief creates a diff as a JSON patch
18523
18524
    Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can
18525
    be changed into the value @a target by calling @ref patch function.
18526
18527
    @invariant For two JSON values @a source and @a target, the following code
18528
    yields always `true`:
18529
    @code {.cpp}
18530
    source.patch(diff(source, target)) == target;
18531
    @endcode
18532
18533
    @note Currently, only `remove`, `add`, and `replace` operations are
18534
          generated.
18535
18536
    @param[in] source  JSON value to compare from
18537
    @param[in] target  JSON value to compare against
18538
    @param[in] path    helper value to create JSON pointers
18539
18540
    @return a JSON patch to convert the @a source to @a target
18541
18542
    @complexity Linear in the lengths of @a source and @a target.
18543
18544
    @liveexample{The following code shows how a JSON patch is created as a
18545
    diff for two JSON values.,diff}
18546
18547
    @sa @ref patch -- apply a JSON patch
18548
    @sa @ref merge_patch -- apply a JSON Merge Patch
18549
18550
    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
18551
18552
    @since version 2.0.0
18553
    */
18554
    static basic_json diff(const basic_json& source, const basic_json& target,
18555
                           const std::string& path = "")
18556
    {
18557
        // the patch
18558
        basic_json result(value_t::array);
18559
18560
        // if the values are the same, return empty patch
18561
        if (source == target)
18562
        {
18563
            return result;
18564
        }
18565
18566
        if (source.type() != target.type())
18567
        {
18568
            // different types: replace value
18569
            result.push_back(
18570
            {
18571
                {"op", "replace"}, {"path", path}, {"value", target}
18572
            });
18573
        }
18574
        else
18575
        {
18576
            switch (source.type())
18577
            {
18578
                case value_t::array:
18579
                {
18580
                    // first pass: traverse common elements
18581
                    std::size_t i = 0;
18582
                    while (i < source.size() and i < target.size())
18583
                    {
18584
                        // recursive call to compare array values at index i
18585
                        auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
18586
                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());
18587
                        ++i;
18588
                    }
18589
18590
                    // i now reached the end of at least one array
18591
                    // in a second pass, traverse the remaining elements
18592
18593
                    // remove my remaining elements
18594
                    const auto end_index = static_cast<difference_type>(result.size());
18595
                    while (i < source.size())
18596
                    {
18597
                        // add operations in reverse order to avoid invalid
18598
                        // indices
18599
                        result.insert(result.begin() + end_index, object(
18600
                        {
18601
                            {"op", "remove"},
18602
                            {"path", path + "/" + std::to_string(i)}
18603
                        }));
18604
                        ++i;
18605
                    }
18606
18607
                    // add other remaining elements
18608
                    while (i < target.size())
18609
                    {
18610
                        result.push_back(
18611
                        {
18612
                            {"op", "add"},
18613
                            {"path", path + "/" + std::to_string(i)},
18614
                            {"value", target[i]}
18615
                        });
18616
                        ++i;
18617
                    }
18618
18619
                    break;
18620
                }
18621
18622
                case value_t::object:
18623
                {
18624
                    // first pass: traverse this object's elements
18625
                    for (auto it = source.cbegin(); it != source.cend(); ++it)
18626
                    {
18627
                        // escape the key name to be used in a JSON patch
18628
                        const auto key = json_pointer::escape(it.key());
18629
18630
                        if (target.find(it.key()) != target.end())
18631
                        {
18632
                            // recursive call to compare object values at key it
18633
                            auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
18634
                            result.insert(result.end(), temp_diff.begin(), temp_diff.end());
18635
                        }
18636
                        else
18637
                        {
18638
                            // found a key that is not in o -> remove it
18639
                            result.push_back(object(
18640
                            {
18641
                                {"op", "remove"}, {"path", path + "/" + key}
18642
                            }));
18643
                        }
18644
                    }
18645
18646
                    // second pass: traverse other object's elements
18647
                    for (auto it = target.cbegin(); it != target.cend(); ++it)
18648
                    {
18649
                        if (source.find(it.key()) == source.end())
18650
                        {
18651
                            // found a key that is not in this -> add it
18652
                            const auto key = json_pointer::escape(it.key());
18653
                            result.push_back(
18654
                            {
18655
                                {"op", "add"}, {"path", path + "/" + key},
18656
                                {"value", it.value()}
18657
                            });
18658
                        }
18659
                    }
18660
18661
                    break;
18662
                }
18663
18664
                default:
18665
                {
18666
                    // both primitive type: replace value
18667
                    result.push_back(
18668
                    {
18669
                        {"op", "replace"}, {"path", path}, {"value", target}
18670
                    });
18671
                    break;
18672
                }
18673
            }
18674
        }
18675
18676
        return result;
18677
    }
18678
18679
    /// @}
18680
18681
    ////////////////////////////////
18682
    // JSON Merge Patch functions //
18683
    ////////////////////////////////
18684
18685
    /// @name JSON Merge Patch functions
18686
    /// @{
18687
18688
    /*!
18689
    @brief applies a JSON Merge Patch
18690
18691
    The merge patch format is primarily intended for use with the HTTP PATCH
18692
    method as a means of describing a set of modifications to a target
18693
    resource's content. This function applies a merge patch to the current
18694
    JSON value.
18695
18696
    The function implements the following algorithm from Section 2 of
18697
    [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):
18698
18699
    ```
18700
    define MergePatch(Target, Patch):
18701
      if Patch is an Object:
18702
        if Target is not an Object:
18703
          Target = {} // Ignore the contents and set it to an empty Object
18704
        for each Name/Value pair in Patch:
18705
          if Value is null:
18706
            if Name exists in Target:
18707
              remove the Name/Value pair from Target
18708
          else:
18709
            Target[Name] = MergePatch(Target[Name], Value)
18710
        return Target
18711
      else:
18712
        return Patch
18713
    ```
18714
18715
    Thereby, `Target` is the current object; that is, the patch is applied to
18716
    the current value.
18717
18718
    @param[in] patch  the patch to apply
18719
18720
    @complexity Linear in the lengths of @a patch.
18721
18722
    @liveexample{The following code shows how a JSON Merge Patch is applied to
18723
    a JSON document.,merge_patch}
18724
18725
    @sa @ref patch -- apply a JSON patch
18726
    @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)
18727
18728
    @since version 3.0.0
18729
    */
18730
    void merge_patch(const basic_json& patch)
18731
    {
18732
        if (patch.is_object())
18733
        {
18734
            if (not is_object())
18735
            {
18736
                *this = object();
18737
            }
18738
            for (auto it = patch.begin(); it != patch.end(); ++it)
18739
            {
18740
                if (it.value().is_null())
18741
                {
18742
                    erase(it.key());
18743
                }
18744
                else
18745
                {
18746
                    operator[](it.key()).merge_patch(it.value());
18747
                }
18748
            }
18749
        }
18750
        else
18751
        {
18752
            *this = patch;
18753
        }
18754
    }
18755
18756
    /// @}
18757
};
18758
} // namespace nlohmann
18759
18760
///////////////////////
18761
// nonmember support //
18762
///////////////////////
18763
18764
// specialization of std::swap, and std::hash
18765
namespace std
18766
{
18767
18768
/// hash value for JSON objects
18769
template<>
18770
struct hash<nlohmann::json>
18771
{
18772
    /*!
18773
    @brief return a hash value for a JSON object
18774
18775
    @since version 1.0.0
18776
    */
18777
    std::size_t operator()(const nlohmann::json& j) const
0
18778
    {
0
18779
        // a naive hashing via the string representation
0
18780
        const auto& h = hash<nlohmann::json::string_t>();
0
18781
        return h(j.dump());
0
18782
    }
18783
};
18784
18785
/// specialization for std::less<value_t>
18786
/// @note: do not remove the space after '<',
18787
///        see https://github.com/nlohmann/json/pull/679
18788
template<>
18789
struct less< ::nlohmann::detail::value_t>
18790
{
18791
    /*!
18792
    @brief compare two value_t enum values
18793
    @since version 3.0.0
18794
    */
18795
    bool operator()(nlohmann::detail::value_t lhs,
18796
                    nlohmann::detail::value_t rhs) const noexcept
0
18797
    {
0
18798
        return nlohmann::detail::operator<(lhs, rhs);
0
18799
    }
18800
};
18801
18802
/*!
18803
@brief exchanges the values of two JSON objects
18804
18805
@since version 1.0.0
18806
*/
18807
template<>
18808
inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(
18809
    is_nothrow_move_constructible<nlohmann::json>::value and
18810
    is_nothrow_move_assignable<nlohmann::json>::value
18811
)
0
18812
{
0
18813
    j1.swap(j2);
0
18814
}
18815
18816
} // namespace std
18817
18818
/*!
18819
@brief user-defined string literal for JSON values
18820
18821
This operator implements a user-defined string literal for JSON objects. It
18822
can be used by adding `"_json"` to a string literal and returns a JSON object
18823
if no parse error occurred.
18824
18825
@param[in] s  a string representation of a JSON object
18826
@param[in] n  the length of string @a s
18827
@return a JSON object
18828
18829
@since version 1.0.0
18830
*/
18831
inline nlohmann::json operator "" _json(const char* s, std::size_t n)
0
18832
{
0
18833
    return nlohmann::json::parse(s, s + n);
0
18834
}
18835
18836
/*!
18837
@brief user-defined string literal for JSON pointer
18838
18839
This operator implements a user-defined string literal for JSON Pointers. It
18840
can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer
18841
object if no parse error occurred.
18842
18843
@param[in] s  a string representation of a JSON Pointer
18844
@param[in] n  the length of string @a s
18845
@return a JSON pointer object
18846
18847
@since version 2.0.0
18848
*/
18849
inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
0
18850
{
0
18851
    return nlohmann::json::json_pointer(std::string(s, n));
0
18852
}
18853
18854
// #include <nlohmann/detail/macro_unscope.hpp>
18855
18856
18857
// restore GCC/clang diagnostic settings
18858
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
18859
    #pragma GCC diagnostic pop
18860
#endif
18861
#if defined(__clang__)
18862
    #pragma GCC diagnostic pop
18863
#endif
18864
18865
// clean up
18866
#undef JSON_INTERNAL_CATCH
18867
#undef JSON_CATCH
18868
#undef JSON_THROW
18869
#undef JSON_TRY
18870
#undef JSON_LIKELY
18871
#undef JSON_UNLIKELY
18872
#undef JSON_DEPRECATED
18873
#undef JSON_HAS_CPP_14
18874
#undef JSON_HAS_CPP_17
18875
#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
18876
#undef NLOHMANN_BASIC_JSON_TPL
18877
18878
18879
#endif
/home/cyniu/GIT/malina/iDom_server_OOP/test/iDom_TESTs-CMAKE/../../test/iDom_TESTs-CMAKE/../../../iDom_server_OOP/src/iDomTools/test/../../RADIO_433_eq/../433MHz/RFLink/../../iDom_server_OOP.h
1
#ifndef GLOBAL_H
2
#define GLOBAL_H
3
4
#include <iostream>
5
#include <fstream>
6
#include <string>
7
#include <cstdlib>
8
#include <pthread.h>
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <sys/socket.h>
12
#include <sys/types.h>
13
#include <netinet/in.h>
14
#include <vector>
15
#include <thread>
16
#include <arpa/inet.h>
17
#include <netinet/in.h>
18
#include <unistd.h>
19
#include <sys/fcntl.h>
20
#include <unistd.h>
21
#include <errno.h>
22
#include <signal.h>
23
#include <time.h>
24
#include <wiringPi.h>
25
#include <chrono>
26
27
// MOJE BIBLIOTEKI
28
#include "KEY/key.h"
29
#include "logger/logger.hpp"
30
#include "files_tree/files_tree.h"
31
#include "menu_tree/menu_tree.h"
32
#include "LCD_c/lcd_c.h"
33
#include "command/command.h"
34
#include "../libs/event_counters/event_counters_handler.h"
35
#include "iDomTools/idomtools.h"
36
#include "iDomStatus/idomstatus.h"
37
#include "iDomSaveState/idom_save_state.h"
38
39
#define log_file_cout  f_log //std::cout   zmien f_log na std::cout  i bedzie wypisywac na ekran
40
#define log_file_mutex f_log
41
42
enum class iDomStateEnum{
43
    CLOSE = 0,
44
    RELOAD,
45
    ERROR,
46
    WORKING,
47
    HARD_RELOAD
48
};
49
50
namespace iDomConst
51
{
52
constexpr int MAX_CONNECTION = 10;
53
constexpr int FREE  = 1;
54
constexpr int RS232 = 11;
55
constexpr int CLOCK = 12;
56
constexpr int ok    =  0;
57
constexpr int GPIO_SPIK  = 21;
58
constexpr int GPIO_PRINTER = 22;
59
constexpr int BUTTON_PIN = 25;
60
}
61
struct ALERT
62
{
63
    Clock time;
64
    STATE state = STATE::DEACTIVE;
65
    unsigned int fromVolume =  48;
66
    unsigned int toVolume = 58;
67
    unsigned int radioID = 8;
68
};
69
70
extern std::string  _logfile  ;
71
extern Logger log_file_mutex;
72
extern std::string buffer;
73
74
enum class TEMPERATURE_STATE;
75
enum class PILOT_KEY;
76
77
struct MPD_info{
78
    std::string title   = "NULL";
79
    std::string radio   = "NULL";
80
    std::string artist  = "NULL";
81
    int volume  = 0;
82
    bool isPlay = false;
83
    int currentSongID = 0;
84
    std::vector <std::string> songList = {"NULL"};
85
};
86
struct s_pointer{
87
    unsigned int *ptr_who;
88
    int32_t *ptr_buf;
89
};
90
91
struct Thread_array_struc {
92
    std::thread thread;
93
    std::thread::id thread_ID = std::thread::id(0);
94
    std::string thread_name;
95
    int thread_socket = 0;
96
};
97
98
struct address_another_servers {
99
    int id;
100
    std::string SERVER_IP;
101
};
102
103
struct FTP_SERVER{
104
    std::string URL;
105
    std::string user;
106
    std::string pass;
107
};
108
struct iDOM_STATE{
109
    STATE houseState = STATE::UNDEFINE;
110
111
};
112
113
struct config{
114
    std::string portRS232;
115
    std::string portRS232_clock;
116
    std::string BaudRate;
117
    std::string RFLinkPort;
118
    std::string RFLinkBaudRate;
119
    int PORT;
120
    std::string SERVER_IP;
121
    std::string MPD_IP;
122
    std::string MOVIES_DB_PATH;
123
    std::string MENU_PATH;
124
    std::string THREAD_MPD   = "NULL";
125
    std::string THREAD_IRDA  = "NULL";
126
    std::string THREAD_CRON  = "NULL";
127
    std::string THREAD_RS232 = "NULL";
128
    std::string THREAD_DUMMY = "NULL";
129
    std::string TS_KEY= " gg ";
130
    std::string cameraLedON = "";
131
    std::string cameraLedOFF ="";
132
    std::string cameraURL="";
133
    std::string facebookAccessToken = "";
134
    std::string viberToken = "NULL";
135
    std::string viberAvatar;
136
    std::vector <std::string> viberReceiver;
137
    std::string viberSender;
138
    std::string radio433MHzConfigFile;
139
    std::string omxplayerFile = "NULL";
140
    int ID_server = 0;
141
    int v_delay  ;
142
    bool encrypted = true;
143
144
    FTP_SERVER ftpServer;
145
    std::string lightningApiURL = "NULL";
146
    std::string saveFilePath = "NULL";
147
};
148
149
struct LED_Strip{
150
    std::string from ;
151
    std::string to ;
152
    std::string R ;
153
    std::string G ;
154
    std::string B ;
155
    std::string colorName;
156
157
    LED_Strip (int from, int to, int r, int g, int b, std::string colorName = "NULL"):from(std::to_string(from)),
158
        to(std::to_string(to)),
159
        R(std::to_string(r)),
160
        G(std::to_string(g)),
161
        B(std::to_string(b)),
162
        colorName(colorName)
434
163
    {
434
164
434
165
    }
166
    LED_Strip (std::string from, std::string to, std::string r, std::string g, std::string b, std::string colorName = "NULL"):
167
        from(from),
168
        to(to),
169
        R(r),
170
        G(g),
171
        B(b),
172
        colorName(colorName)
0
173
    {
0
174
0
175
    }
176
0
177
    void set (std::string from, std::string to, std::string r, std::string g, std::string b, std::string colorName = "NULL"){
0
178
        this->from =from;
0
179
        this->to = to;
0
180
        R = r;
0
181
        G = g;
0
182
        B = b;
0
183
        this->colorName =colorName;
0
184
    }
185
0
186
    void set (int from, int to, int r, int g, int b, std::string colorName = "NULL"){
0
187
        this->from = std::to_string(from);
0
188
        this->to = std::to_string(to);
0
189
        R = std::to_string(r);
0
190
        G = std::to_string(g);
0
191
        B = std::to_string(b);
0
192
        this->colorName =colorName;
0
193
    }
194
0
195
    std::string getColorName() const{
0
196
        return colorName;
0
197
    }
198
199
    std::string get(unsigned int _from, unsigned int _to) const{
200
        if (_from != 0 || _to != 60){
201
            return "LED:["+std::to_string(_from)+"-"+std::to_string(_to)+"-"+R+"-"+G+"-"+B+"];";
202
        }
203
        return "LED:["+from+"-"+to+"-"+R+"-"+G+"-"+B+"];";
204
    }
205
0
206
    std::string makeCommand(std::string from, std::string to, std::string R, std::string G, std::string B){
0
207
        return "LED:["+from+"-"+to+"-"+R+"-"+G+"-"+B+"];";
0
208
    }
209
};
210
211
struct pilot_led{
212
    unsigned int counter=0;
213
    std::vector<LED_Strip> colorLED   = { LED_Strip(1,60,237,145,33 ,"carrot orange"),
214
                                          LED_Strip(1,60,255,0,0    ,"red"),
215
                                          LED_Strip(1,60,0,255,0    ,"green"),
216
                                          LED_Strip(1,60,0,0,255    ,"blue"),
217
                                          LED_Strip(1,60,255,255,255,"white"),
218
                                          LED_Strip(1,60,255,255,0  ,"yellow"),
219
                                          LED_Strip(1,60,0,255,255  ,"cyan"),
220
                                          LED_Strip(1,60,255,0,255  ,"magenta")
221
                                        };
222
};
223
224
class command ;  // for struc thread_data req
225
class iDomTOOLS;
226
class RADIO_EQ_CONTAINER;
227
class RFLinkHandler;
228
229
struct thread_data{
230
    int s_client_sock;
231
    struct sockaddr_in from;
232
    struct config *server_settings = NULL;
233
    struct s_pointer pointer;
234
    LCD_c *mainLCD = NULL;
235
    files_tree *main_tree = NULL;
236
    menu_tree *main_MENU = NULL;
237
    iDomTOOLS *main_iDomTools = NULL;
238
    RFLinkHandler *main_RFLink = NULL;
239
    Thread_array_struc *main_THREAD_arr = NULL;
240
    time_t start;
241
    time_t now_time;
242
    int sleeper;
243
    std::map <std::string, std::unique_ptr <KEY>  > key_map;
244
    MPD_info *ptr_MPD_info = NULL;
245
    pilot_led * ptr_pilot_led = NULL;
246
    std::map <std::string, std::unique_ptr<command> >* commandMapPtr = NULL;
247
    event_counters_handler myEventHandler;
248
    std::string encriptionKey = "40%";
249
    iDomSTATUS *main_iDomStatus;
250
    iDOM_STATE idom_all_state;
251
    ALERT alarmTime;
252
    RADIO_EQ_CONTAINER *main_REC;
253
    iDomStateEnum iDomProgramState = iDomStateEnum::WORKING;
254
255
};
256
257
struct thread_data_rs232{
258
    std::string portRS232;
259
    std::string portRS232_clock;
260
    std::string BaudRate;
261
    struct s_pointer pointer;
262
};
263
264
#endif // GLOBAL_H
/home/cyniu/GIT/malina/iDom_server_OOP/test/iDom_TESTs-CMAKE/../../test/iDom_TESTs-CMAKE/../../../iDom_server_OOP/src/iDomTools/test/../lightning.h
1
#ifndef LIGHTNING_H
2
#define LIGHTNING_H
3
#include <iostream>
4
5
#include "../../libs/Statistic/statistic.h"
6
#include "../../libs/useful/useful.h"
7
8
#include "idomtools_useful.h"
9
#include "json.hpp"
10
11
class CARDINAL_DIRECTIONS{
12
public:
13
    enum class CARDINAL_DIRECTIONS_ENUM{
14
        /*
15
           N
16
        NNW NNE
17
      NW       NE
18
   WNW		     ENE
19
 W				    E
20
   WSW			 ESE
21
      SW	   SE
22
        SSW	 SSE
23
           S
24
    */
25
26
        N = 1,NNE,NE,ENE,E,ESE,SE,SSE,S,SSW,SW,WSW,W,WNW,NW,NNW,ERROR
27
    };
28
    static CARDINAL_DIRECTIONS_ENUM stringToCardinalDirectionsEnum(std::string s){
29
        if (s == "N")      return CARDINAL_DIRECTIONS_ENUM::N;
30
        else if (s == "NNE")    return CARDINAL_DIRECTIONS_ENUM::NNE;
31
        else if (s == "NE")     return CARDINAL_DIRECTIONS_ENUM::NE;
32
        else if (s == "ENE")    return CARDINAL_DIRECTIONS_ENUM::ENE;
33
        else if (s == "E")      return CARDINAL_DIRECTIONS_ENUM::E;
34
        else if (s == "ESE")    return CARDINAL_DIRECTIONS_ENUM::ESE;
35
        else if (s == "SE")     return CARDINAL_DIRECTIONS_ENUM::SE;
36
        else if (s == "SSE")    return CARDINAL_DIRECTIONS_ENUM::SSE;
37
        else if (s == "S")      return CARDINAL_DIRECTIONS_ENUM::S;
38
        else if (s == "SSW")    return CARDINAL_DIRECTIONS_ENUM::SSW;
39
        else if (s == "SW")     return CARDINAL_DIRECTIONS_ENUM::SW;
40
        else if (s == "WSW")    return CARDINAL_DIRECTIONS_ENUM::WSW;
41
        else if (s == "W")      return CARDINAL_DIRECTIONS_ENUM::W;
42
        else if (s == "WNW")    return CARDINAL_DIRECTIONS_ENUM::WNW;
43
        else if (s == "NW")     return CARDINAL_DIRECTIONS_ENUM::NW;
44
        else if (s == "NNW")    return CARDINAL_DIRECTIONS_ENUM::NNW;
45
        else                    return CARDINAL_DIRECTIONS_ENUM::ERROR;
46
    }
47
48
    static std::string cardinalDirectionsEnumToString(CARDINAL_DIRECTIONS_ENUM e){
49
        switch (e){
50
        case CARDINAL_DIRECTIONS_ENUM::N:
51
            return "N";
52
        case CARDINAL_DIRECTIONS_ENUM::NNE:
53
            return "NNE";
54
        case CARDINAL_DIRECTIONS_ENUM:: NE:
55
            return "NE";
56
        case CARDINAL_DIRECTIONS_ENUM::ENE:
57
            return "ENE";
58
        case CARDINAL_DIRECTIONS_ENUM::E:
59
            return "E";
60
        case CARDINAL_DIRECTIONS_ENUM::ESE:
61
            return "ESE";
62
        case CARDINAL_DIRECTIONS_ENUM::SE:
63
            return "SE";
64
        case CARDINAL_DIRECTIONS_ENUM::SSE:
65
            return "SSE";
66
        case CARDINAL_DIRECTIONS_ENUM::S:
67
            return "S";
68
        case CARDINAL_DIRECTIONS_ENUM::SSW:
69
            return "SSW";
70
        case CARDINAL_DIRECTIONS_ENUM::SW:
71
            return "SW";
72
        case CARDINAL_DIRECTIONS_ENUM::WSW:
73
            return "WSW";
74
        case CARDINAL_DIRECTIONS_ENUM::W:
75
            return "W";
76
        case CARDINAL_DIRECTIONS_ENUM::WNW:
77
            return "WNW";
78
        case CARDINAL_DIRECTIONS_ENUM::NW:
79
            return "NW";
80
        case CARDINAL_DIRECTIONS_ENUM::NNW:
81
            return "NNW";
82
        default:
83
            return "UNKNOWN DIRECTION";
84
        }
85
    }
86
    static std::string cardinalDirectionsEnumToHuman(CARDINAL_DIRECTIONS_ENUM e){
87
        switch (e){
88
        case CARDINAL_DIRECTIONS_ENUM::N:
89
            return "północ";
90
        case CARDINAL_DIRECTIONS_ENUM::NNE:
91
            return "północ - północny wschód";
92
        case CARDINAL_DIRECTIONS_ENUM:: NE:
93
            return "północny wschód";
94
        case CARDINAL_DIRECTIONS_ENUM::ENE:
95
            return "wschód - północny wschód";
96
        case CARDINAL_DIRECTIONS_ENUM::E:
97
            return "wschód";
98
        case CARDINAL_DIRECTIONS_ENUM::ESE:
99
            return "wschód - południowy wschód";
100
        case CARDINAL_DIRECTIONS_ENUM::SE:
101
            return "południowy wschód";
102
        case CARDINAL_DIRECTIONS_ENUM::SSE:
103
            return "południe - południowy wschód";
104
        case CARDINAL_DIRECTIONS_ENUM::S:
105
            return "południe";
106
        case CARDINAL_DIRECTIONS_ENUM::SSW:
107
            return "południe - południowy zachów";
108
        case CARDINAL_DIRECTIONS_ENUM::SW:
109
            return "południowy zachów";
110
        case CARDINAL_DIRECTIONS_ENUM::WSW:
111
            return "zachód - południowy zachów";
112
        case CARDINAL_DIRECTIONS_ENUM::W:
113
            return "zachód";
114
        case CARDINAL_DIRECTIONS_ENUM::WNW:
115
            return "zachód - północny zachód";
116
        case CARDINAL_DIRECTIONS_ENUM::NW:
117
            return "północny zachód";
118
        case CARDINAL_DIRECTIONS_ENUM::NNW:
119
            return "północ - północny zachód";
120
        default:
121
            return "UNKNOWN DIRECTION";
122
        }
123
    }
124
    struct ALARM_INFO{
125
        ALARM_INFO():
126
            riseAlarm(false),
127
            timestamp(0),
128
            distance(0.0),
129
            bearingENG(CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::ERROR)
124
130
        {
124
131
            data << "NULL";
124
132
        }
133
        ALARM_INFO(const ALARM_INFO &s):
134
            riseAlarm(s.riseAlarm),
135
            data(s.data.str()),
136
            timestamp(s.timestamp),
137
            distance(s.distance),
138
            bearingENG(s.bearingENG)
139
        {
140
        }
141
        ALARM_INFO& operator = (const ALARM_INFO& s)
142
        {
143
            this->data.str(std::string());
144
            this->riseAlarm = s.riseAlarm;
145
            this->data << s.data.str();
146
            this->timestamp = s.timestamp;
147
            this->distance = s.distance;
148
            this->bearingENG = s.bearingENG;
149
            return *this;
150
        }
151
152
        bool riseAlarm;
153
        std::stringstream data;
154
        unsigned int timestamp; //second
155
        double distance;  //km
156
        CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM bearingENG;
157
    };
158
};
159
160
class LIGHTNING
161
{
162
public:
163
    LIGHTNING();
164
    ~LIGHTNING();
165
    CARDINAL_DIRECTIONS::ALARM_INFO lightningAlert(nlohmann::json jj);
166
    bool checkLightningAlert(CARDINAL_DIRECTIONS::ALARM_INFO* info);
167
private:
168
    bool alarmState = false;
169
    Clock lightningTime;    
170
    double oldDistance = 0.0;
171
};
172
173
#endif // LIGHTNING_H
/home/cyniu/GIT/malina/iDom_server_OOP/test/iDom_TESTs-CMAKE/../../test/iDom_TESTs-CMAKE/../../../iDom_server_OOP/src/iDomTools/test/iDomTools_fixture.h
1
#include <gtest/gtest.h>
2
#include "test_data.h"
3
#include "../idomtools.h"
4
#include "../../src/functions/functions.h"
5
#include "../../RADIO_433_eq/radio_433_eq.h"
6
#include "testJSON.h"
7
8
class iDomTOOLS_ClassTest : public ::testing::Test
9
{
10
public:
11
    TEST_JSON test_Json;
12
    LIGHTNING test_lightning;
13
    CARDINAL_DIRECTIONS::ALARM_INFO test_struct;
14
    thread_data test_my_data;
15
    iDomSTATUS test_status;
16
    config test_server_set;
17
    RADIO_EQ_CONTAINER test_rec;
18
    iDOM_STATE main_iDomStatus;
19
    ALERT test_alarmTime;
20
    pilot_led test_pilot_led;
21
22
    /// pointer
23
    iDomTOOLS* test_idomTOOLS;
24
    /////// method
25
    iDomTOOLS_ClassTest():test_rec(&test_my_data)
53
26
    {
53
27
        std::cout << "konstruktor testu " <<std::endl;
53
28
    }
29
    void SetUp()
53
30
    {
53
31
        std::cout << "SetUP testu iDomTOOLS_ClassTest" <<std::endl;
53
32
        test_server_set.TS_KEY = "key test";
53
33
        test_server_set.viberSender = "test sender";
53
34
        test_server_set.viberReceiver = {"R1","R2"};
53
35
        test_server_set.saveFilePath = "/mnt/ramdisk/iDomStateTest2.save";
53
36
        test_server_set.radio433MHzConfigFile = "/mnt/ramdisk/433_eq_conf.json";
53
37
        test_rec.loadConfig(test_server_set.radio433MHzConfigFile);
53
38
53
39
        test_my_data.main_REC = (&test_rec);
53
40
        test_my_data.server_settings = &test_server_set;
53
41
        test_my_data.main_iDomStatus = &test_status;
53
42
        test_my_data.alarmTime = test_alarmTime;
53
43
        test_my_data.idom_all_state = main_iDomStatus;
53
44
        test_my_data.ptr_pilot_led = &test_pilot_led;
53
45
53
46
        test_status.addObject("house");
53
47
53
48
        /////////// create
53
49
        test_idomTOOLS = new iDomTOOLS(&test_my_data);
53
50
53
51
        test_my_data.main_iDomTools = test_idomTOOLS;
53
52
        useful_F::myStaticData = &test_my_data;
53
53
    }
54
55
    void TearDown()
53
56
    {
53
57
        delete test_idomTOOLS;
53
58
    }
59
};
60
/home/cyniu/GIT/malina/iDom_server_OOP/test/iDom_TESTs-CMAKE/../../test/iDom_TESTs-CMAKE/../../src/functions/../blockQueue/../logger/logger.hpp
1
/*
2
 * logger.hpp
3
 *
4
 *
5
 * Logger Library Header
6
 *
7
 *
8
 * Copyright (C) 2013-2014  Bryant Moscon - bmoscon@gmail.com
9
 *
10
 * Permission is hereby granted, free of charge, to any person obtaining a copy
11
 * of this software and associated documentation files (the "Software"), to
12
 * deal in the Software without restriction, including without limitation the
13
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
14
 * sell copies of the Software, and to permit persons to whom the Software is
15
 * furnished to do so, subject to the following conditions:
16
 *
17
 * 1. Redistributions of source code must retain the above copyright notice,
18
 *    this list of conditions, and the following disclaimer.
19
 *
20
 * 2. Redistributions in binary form must reproduce the above copyright notice,
21
 *    this list of conditions and the following disclaimer in the documentation
22
 *    and/or other materials provided with the distribution, and in the same
23
 *    place and form as other copyright, license and disclaimer information.
24
 *
25
 * 3. The end-user documentation included with the redistribution, if any, must
26
 *    include the following acknowledgment: "This product includes software
27
 *    developed by Bryant Moscon (http://www.bryantmoscon.org/)", in the same
28
 *    place and form as other third-party acknowledgments. Alternately, this
29
 *    acknowledgment may appear in the software itself, in the same form and
30
 *    location as other such third-party acknowledgments.
31
 *
32
 * 4. Except as contained in this notice, the name of the author, Bryant Moscon,
33
 *    shall not be used in advertising or otherwise to promote the sale, use or
34
 *    other dealings in this Software without prior written authorization from
35
 *    the author.
36
 *
37
 *
38
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
41
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
 * THE SOFTWARE.
45
 *
46
 */
47
#ifndef __LOGGER__
48
#define __LOGGER__
49
50
#include <fstream>
51
#include <cassert>
52
#include <ctime>
53
#include <sstream>
54
55
// Log levels
56
typedef enum {
57
    US =0,
58
    VERBOSE,
59
    DEBUG,
60
    INFO,
61
    WARNING,
62
    ERROR,
63
    CRITICAL,
64
    FATAL
65
} logger_level;
66
67
class Logger : public std::ostringstream {
68
public:
69
70
    explicit Logger(const char *f);
71
    explicit Logger(const std::string& f);
72
    Logger (const Logger &) ;
73
    Logger &operator= (const Logger &) ;
74
    ~Logger();
75
    static pthread_mutex_t mutex_log ;
76
77
    void set_level(const logger_level& level);
78
    void flush();
79
    void mutex_lock();
80
    void mutex_unlock();
81
82
    template <typename T>
83
    Logger& operator<<(const T& t)
84
    {
85
        *static_cast<std::ostringstream *>(this) << t;
86
        return (*this);
87
    }
88
89
    Logger& operator<<(const logger_level& level);
90
    typedef Logger& (* LoggerManip)(Logger&);
91
    Logger& operator<<(LoggerManip m);
92
93
private:
94
    std::string get_time() const;
95
    inline const char* level_str(const logger_level& level);
96
public:
97
    std::ofstream  _file;
98
private:
99
    std::ostream&  _log;
100
    logger_level   _level;
101
    logger_level   _line_level;
102
};
103
104
105
namespace std { 
106
inline Logger& endl(Logger& out)
0
107
{
0
108
    out.put('\n');
0
109
    out.flush();
0
110
    return (out);
0
111
}
112
}// end namespace std
113
114
#endif
/home/cyniu/GIT/malina/iDom_server_OOP/test/iDom_TESTs-CMAKE/main.cpp
1
#include <iostream>
2
#include <gtest/gtest.h>
3
#include <gmock/gmock.h>
4
#include <gconv.h>
5
#include <fstream>
6
#include <sstream>
7
8
class test_433
9
{
10
public:
11
    std::string config433 = "{ \"BUTTON\": { \"locker\": { \"OFF\": \"NULL\", \"ON\": \"NULL\", \"id\": \"01e7be\", \"name\": \"locker\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\", \"type\": \"BUTTON\" } }, \"SWITCH\": { \"A\": { \"OFF\": \"10;TriState;0280aa;0;OFF\", \"ON\": \"10;TriState;0280aa;0;ON\", \"id\": \"1444\", \"name\": \"A\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"null\", \"unlock\": \"null\", \"type\": \"SWITCH\" }, \"ALARM\": { \"OFF\": \"dummyOFF\", \"ON\": \"dummyON\", \"id\": \"1223\", \"name\": \"ALARM\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"null\", \"unlock\": \"null\", \"type\": \"SWITCH\" }, \"B\": { \"OFF\": \"10;TriState;02822a;0;OFF\", \"ON\": \"10;TriState;02822a;0;ON\", \"id\": \"1445\", \"name\": \"B\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\", \"lock\": \"null\", \"unlock\": \"null\",\"type\": \"SWITCH\" }, \"C\": { \"OFF\": \"10;TriState;02828a;0;OFF\", \"ON\": \"10;TriState;02828a;0;ON\", \"id\": \"1446\", \"name\": \"C\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\", \"lock\": \"null\", \"unlock\": \"null\",\"type\": \"SWITCH\" }, \"listwa\": { \"OFF\": \"10;Kaku;0ad04d;15;OFF\", \"ON\": \"10;Kaku;0ad04d;15;ON\", \"id\": \"1450\", \"name\": \"listwa\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"OFF\", \"unlock\": \"ON\", \"type\": \"SWITCH\" } }, \"WEATHER\": { \"first\": { \"OFF\": \"NULL\", \"ON\": \"NULL\", \"id\": \"0704\", \"name\": \"first\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\", \"type\": \"WEATHER\" } } }";
12
    std::string config433_fake = "{ \"BUTTON\": { \"locker\": { \"OFF\": \"NULL\", \"ON\": \"NULL\", \"id\": \"01e7be\", \"name\": \"locker\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\", \"type\": \"BUTTON\" } }, \"SWITCH\": { \"A\": { \"OFF\": \"10;TriState;0280aa;0;OFF\", \"ON\": \"10;TriState;0280aa;0;ON\", \"id\": \"1444\", \"name\": \"A\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"null\", \"unlock\": \"null\", \"type\": \"SWITCH\" }, \"ALARM\": { \"OFF\": \"dummyOFF\", \"ON\": \"dummyON\", \"id\": \"1223\", \"name\": \"ALARM\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"null\", \"unlock\": \"null\", \"type\": \"SWITCH\" }, \"B\": { \"OFF\": \"10;TriState;02822a;0;OFF\", \"ON\": \"10;TriState;02822a;0;ON\", \"id\": \"1445\", \"name\": \"B\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\", \"lock\": \"null\", \"unlock\": \"null\",\"type\": \"SWITCH\" }, \"C\": { \"OFF\": \"10;TriState;02828a;0;OFF\", \"ON\": \"10;TriState;02828a;0;ON\", \"id\": \"1446\", \"name\": \"C\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"null\", \"unlock\": \"null\", \"type\": \"SWITCH\" }, \"listwa\": { \"OFF\": \"10;Kaku;0ad04d;15;OFF\", \"ON\": \"10;Kaku;0ad04d;15;ON\", \"id\": \"1450\", \"name\": \"listwa\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"OFF\", \"unlock\": \"null\", \"type\": \"SWITCH\" } } } }";
13
14
    void makeFile(const std::string& path)
1
15
    {
1
16
         std::ofstream o(path);
1
17
         o << config433 ;
1
18
    }
19
    void makeFileFake(const std::string& path)
1
20
    {
1
21
         std::ofstream o(path);
1
22
         o << config433_fake ;
1
23
    }
24
};
25
1
26
int main(int argc, char **argv) {
1
27
    test_433 t;
1
28
    t.makeFile("/mnt/ramdisk/433_eq_conf.json");
1
29
    t.makeFileFake("/mnt/ramdisk/433_eq_conf_fake.json");
1
30
1
31
    ::testing::InitGoogleTest( &argc, argv );
1
32
    //::testing::GTEST_FLAG(filter) = "functions_fixture.sleepThread";
1
33
    //::testing::GTEST_FLAG(filter) = "Switch_Class.switch_alarm_on";
1
34
    //::testing::GTEST_FLAG(filter) = "command433MHz_Class_fixture.*)";
1
35
    return RUN_ALL_TESTS();
1
36
}
37